create-sprint 0.0.134 → 0.0.138

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/index.js CHANGED
@@ -5,7 +5,7 @@ import { join } from "path";
5
5
  import color from "picocolors";
6
6
  import * as p from "@clack/prompts";
7
7
  import { validateProjectName } from "./validators.js";
8
- import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
8
+ import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getMainFile, getHomeRoute, getAdminRoute, getUploadRoute, getHomeController, getAdminController, getUploadController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getUploadSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
9
9
  export async function writeFile(path, content, options) {
10
10
  if (typeof content === "string")
11
11
  content = content.trim();
@@ -24,7 +24,7 @@ export async function runCLI(args) {
24
24
  telemetry: options.telemetry ?? "none",
25
25
  swagger: options.swagger ?? true,
26
26
  graphql: options.graphql ?? false,
27
- docker: options.docker || false,
27
+ docker: options.docker || false
28
28
  };
29
29
  }
30
30
  else {
@@ -32,7 +32,7 @@ export async function runCLI(args) {
32
32
  projectName: () => p.text({
33
33
  message: "Project name:",
34
34
  placeholder: "my-api",
35
- validate: (v) => validateProjectName(v || "sprint-app") || undefined,
35
+ validate: (v) => validateProjectName(v || "sprint-app") || undefined
36
36
  }),
37
37
  language: () => p.select({
38
38
  message: "Language:",
@@ -55,12 +55,12 @@ export async function runCLI(args) {
55
55
  }),
56
56
  swagger: () => p.confirm({ message: "Add Swagger UI & OpenAPI?", initialValue: true }),
57
57
  graphql: () => p.confirm({ message: "Add GraphQL support?", initialValue: false }),
58
- docker: () => p.confirm({ message: "Add Docker support?", initialValue: false }),
58
+ docker: () => p.confirm({ message: "Add Docker support?", initialValue: false })
59
59
  }, {
60
60
  onCancel: () => {
61
61
  p.cancel("Cancelled.");
62
62
  process.exit(0);
63
- },
63
+ }
64
64
  });
65
65
  }
66
66
  const targetDir = config.projectName === "." ? process.cwd() : join(process.cwd(), config.projectName);
@@ -102,10 +102,7 @@ export async function runCLI(args) {
102
102
  }
103
103
  }
104
104
  const cdCmd = config.projectName === "." ? "" : `cd ${config.projectName} && `;
105
- p.note([
106
- !installDeps ? `${cdCmd}npm install --include=dev` : "",
107
- `${cdCmd}npm run dev`
108
- ].filter(Boolean).join("\n"), "Next steps");
105
+ p.note([!installDeps ? `${cdCmd}npm install --include=dev` : "", `${cdCmd}npm run dev`].filter(Boolean).join("\n"), "Next steps");
109
106
  p.outro("Ready. Happy shipping.");
110
107
  }
111
108
  ;
@@ -181,9 +178,8 @@ async function createProject(projectName, language, telemetry, swagger, graphql,
181
178
  await mkdir(join(srcDir, "cronjobs"), { recursive: true });
182
179
  await mkdir(join(srcDir, "config"), { recursive: true });
183
180
  await mkdir(join(srcDir, "services"), { recursive: true });
184
- if (graphql) {
181
+ if (graphql)
185
182
  await mkdir(join(srcDir, "graphql"), { recursive: true });
186
- }
187
183
  if (language === "typescript") {
188
184
  await writeFile(join(srcDir, "config", "index.ts"), "");
189
185
  await writeFile(join(srcDir, "config", "clients.ts"), "");
@@ -196,12 +192,15 @@ async function createProject(projectName, language, telemetry, swagger, graphql,
196
192
  await writeFile(join(srcDir, "app." + (language === "typescript" ? "ts" : "js")), getMainFile(language, graphql));
197
193
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
198
194
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
195
+ await writeFile(join(srcDir, "routes", "upload." + (language === "typescript" ? "ts" : "js")), getUploadRoute(language));
199
196
  await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
200
197
  await writeFile(join(srcDir, "controllers", "admin." + (language === "typescript" ? "ts" : "js")), getAdminController(language));
198
+ await writeFile(join(srcDir, "controllers", "upload." + (language === "typescript" ? "ts" : "js")), getUploadController(language));
201
199
  await writeFile(join(srcDir, "middlewares", "auth.internal." + (language === "typescript" ? "ts" : "js")), getInternalAuthMiddleware(language));
202
200
  await writeFile(join(srcDir, "middlewares", "auth.user." + (language === "typescript" ? "ts" : "js")), getUserAuthMiddleware(language));
203
201
  await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
204
202
  await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
203
+ await writeFile(join(srcDir, "schemas", "upload." + (language === "typescript" ? "ts" : "js")), getUploadSchema(language));
205
204
  await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
206
205
  if (graphql) {
207
206
  const graphqlFiles = getGraphQLFiles(language);
@@ -101,3 +101,112 @@ export const jwtGenerateController = (req, res) => {
101
101
  }
102
102
  }
103
103
  ;
104
+ export function getUploadController(language) {
105
+ if (language === "typescript") {
106
+ return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
107
+
108
+ export const uploadPdfController: Handler = (req: SprintRequest, res: SprintResponse) => {
109
+ const file = req.files?.document[0];
110
+
111
+ if (!file) return res.status(400).json({ error: "No file uploaded" });
112
+
113
+ res.json({
114
+ message: "PDF uploaded successfully",
115
+ file: {
116
+ name: file.originalname,
117
+ size: file.size,
118
+ type: file.mimetype
119
+ }
120
+ });
121
+ };
122
+
123
+ export const uploadMultiplePdfsController: Handler = (req: SprintRequest, res: SprintResponse) => {
124
+ const files = req.files?.documents || [];
125
+
126
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
127
+
128
+ res.json({
129
+ message: \`\${files.length} PDFs uploaded successfully\`,
130
+ files: files.map((f) => ({
131
+ name: f.originalname,
132
+ size: f.size,
133
+ type: f.mimetype
134
+ }))
135
+ });
136
+ };
137
+
138
+ export const streamUploadController: Handler = (req: SprintRequest, res: SprintResponse) => {
139
+ const files = (req as any).files?.file || [];
140
+
141
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
142
+
143
+ res.json({
144
+ message: \`\${files.length} file(s) processed via streaming\`,
145
+ files: files.map((f: any) => ({
146
+ fieldName: f.fieldname,
147
+ filename: f.originalname,
148
+ mimeType: f.mimetype,
149
+ encoding: f.encoding
150
+ }))
151
+ });
152
+ };
153
+ `;
154
+ }
155
+ return `export const uploadPdfController = (req, res) => {
156
+ const file = req.file;
157
+
158
+ if (!file) return res.status(400).json({ error: "No file uploaded" });
159
+
160
+ res.json({
161
+ message: "PDF uploaded successfully",
162
+ file: {
163
+ name: file.originalname,
164
+ size: file.size,
165
+ type: file.mimetype
166
+ }
167
+ });
168
+ };
169
+
170
+ export const uploadMultiplePdfsController = (req, res) => {
171
+ const files = req.files?.documents || [];
172
+
173
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
174
+
175
+ res.json({
176
+ message: \`\${files.length} PDFs uploaded successfully\`,
177
+ files: files.map((f) => ({
178
+ name: f.originalname,
179
+ size: f.size,
180
+ type: f.mimetype
181
+ }))
182
+ });
183
+ };
184
+
185
+ export const streamUploadController = async (req, res, next) => {
186
+ const sprint = req.sprintInstance;
187
+
188
+ if (!sprint) return res.status(500).json({ error: "Sprint instance not available" });
189
+
190
+ try {
191
+ const streamParser = sprint.streamUpload({
192
+ limits: { fileSize: 10 * 1024 * 1024 }
193
+ });
194
+
195
+ const { files, fields } = await streamParser(req, res);
196
+
197
+ res.json({
198
+ message: \`\${files.length} file(s) processed via streaming\`,
199
+ files: files.map((f) => ({
200
+ fieldName: f.fieldName,
201
+ filename: f.filename,
202
+ mimeType: f.mimeType,
203
+ encoding: f.encoding
204
+ })),
205
+ fields
206
+ });
207
+ } catch (error) {
208
+ return res.status(400).json({ error: "Stream upload failed", details: error });
209
+ }
210
+ };
211
+ `;
212
+ }
@@ -5,13 +5,13 @@ export { getTsConfig, getSprintConfigFile } from "./configFiles.js";
5
5
  // Environment Files
6
6
  export { getEnvExample, getEnvDevelopment, getEnvProduction } from "./env.js";
7
7
  // Routes
8
- export { getMainFile, getHomeRoute, getAdminRoute } from "./routes.js";
8
+ export { getMainFile, getHomeRoute, getAdminRoute, getUploadRoute } from "./routes.js";
9
9
  // Controllers
10
- export { getHomeController, getAdminController } from "./controllers.js";
10
+ export { getHomeController, getAdminController, getUploadController } from "./controllers.js";
11
11
  // Middlewares
12
12
  export { getInternalAuthMiddleware, getUserAuthMiddleware } from "./middlewares.js";
13
13
  // Schemas
14
- export { getHomeSchema, getAdminSchema } from "./schemas.js";
14
+ export { getHomeSchema, getAdminSchema, getUploadSchema } from "./schemas.js";
15
15
  // Cronjobs
16
16
  export { getExampleCronJob } from "./cronjobs.js";
17
17
  // Docker
@@ -10,7 +10,7 @@ export function generateJWTKeys() {
10
10
  ;
11
11
  export function getTypeScriptPackageJson(name, telemetry, swagger, graphql) {
12
12
  const deps = {
13
- "sprint-es": "^0.0.156"
13
+ "sprint-es": "^0.0.168"
14
14
  };
15
15
  const devDeps = {
16
16
  "@types/node": "^22.0.0",
@@ -22,14 +22,15 @@ export function getTypeScriptPackageJson(name, telemetry, swagger, graphql) {
22
22
  deps["@sentry/node"] = "^8.0.0";
23
23
  else if (telemetry === "discord")
24
24
  deps["axios"] = "^1.6.0";
25
- if (swagger)
25
+ if (swagger) {
26
26
  deps["swagger-ui-express"] = "^5.0.0";
27
- if (swagger)
28
27
  devDeps["@types/swagger-ui-express"] = "^4.1.8";
28
+ }
29
29
  if (graphql) {
30
30
  deps["graphql"] = "^16.13.0";
31
31
  deps["graphql-http"] = "^1.22.4";
32
32
  deps["ruru"] = "^2.0.0-rc.6";
33
+ devDeps["@types/swagger-ui-express"] = "^4.1.8";
33
34
  }
34
35
  return {
35
36
  name: name === "." ? "sprint-app" : name,
@@ -66,7 +67,7 @@ export function getTypeScriptPackageJson(name, telemetry, swagger, graphql) {
66
67
  ;
67
68
  export function getJavaScriptPackageJson(name, telemetry, swagger, graphql) {
68
69
  const deps = {
69
- "sprint-es": "^0.0.156"
70
+ "sprint-es": "^0.0.168"
70
71
  };
71
72
  if (telemetry === "sentry" || telemetry === "glitchtip")
72
73
  deps["@sentry/node"] = "^8.0.0";
@@ -84,3 +84,32 @@ export default router;
84
84
  `;
85
85
  }
86
86
  ;
87
+ export function getUploadRoute(language) {
88
+ if (language === "typescript") {
89
+ return `import { Router } from "sprint-es";
90
+ import { uploadPdfSchema, uploadMultiplePdfsSchema, streamUploadSchema } from "@/schemas/upload";
91
+ import { uploadPdfController, uploadMultiplePdfsController, streamUploadController } from "@/controllers/upload";
92
+
93
+ const router = Router();
94
+
95
+ router.post("/pdf", uploadPdfSchema, uploadPdfController);
96
+ router.post("/pdfs", uploadMultiplePdfsSchema, uploadMultiplePdfsController);
97
+ router.post("/stream", streamUploadSchema, streamUploadController);
98
+
99
+ export default router;
100
+ `;
101
+ }
102
+ return `import { Router } from "sprint-es";
103
+ import { uploadPdfSchema, uploadMultiplePdfsSchema, streamUploadSchema } from "../schemas/upload.js";
104
+ import { uploadPdfController, uploadMultiplePdfsController, streamUploadController } from "../controllers/upload.js";
105
+
106
+ const router = Router();
107
+
108
+ router.post("/pdf", uploadPdfSchema, uploadPdfController);
109
+ router.post("/pdfs", uploadMultiplePdfsSchema, uploadMultiplePdfsController);
110
+ router.post("/stream", streamUploadSchema, streamUploadController);
111
+
112
+ export default router;
113
+ `;
114
+ }
115
+ ;
@@ -54,3 +54,48 @@ export const jwtGenerateSchema = defineRouteSchema({
54
54
  `;
55
55
  }
56
56
  ;
57
+ export function getUploadSchema(language) {
58
+ if (language === "typescript") {
59
+ return `import { z, defineRouteSchema } from "sprint-es/schemas";
60
+
61
+ export const uploadPdfSchema = defineRouteSchema({
62
+ files: {
63
+ document: z.files.format("pdf").maxSize(10 * 1024 * 1024)
64
+ }
65
+ });
66
+
67
+ export const uploadMultiplePdfsSchema = defineRouteSchema({
68
+ files: {
69
+ documents: z.files.format("pdf").maxSize(10 * 1024 * 1024)
70
+ }
71
+ });
72
+
73
+ export const streamUploadSchema = defineRouteSchema({
74
+ files: {
75
+ file: z.files.stream().maxSize(10 * 1024 * 1024)
76
+ }
77
+ });
78
+ `;
79
+ }
80
+ return `import { z, defineRouteSchema } from "sprint-es/schemas";
81
+
82
+ export const uploadPdfSchema = defineRouteSchema({
83
+ files: {
84
+ document: z.files.format("pdf").maxSize(10 * 1024 * 1024)
85
+ }
86
+ });
87
+
88
+ export const uploadMultiplePdfsSchema = defineRouteSchema({
89
+ files: {
90
+ documents: z.files.format("pdf").maxSize(10 * 1024 * 1024)
91
+ }
92
+ });
93
+
94
+ export const streamUploadSchema = defineRouteSchema({
95
+ files: {
96
+ file: z.files.stream().maxSize(10 * 1024 * 1024)
97
+ }
98
+ });
99
+ `;
100
+ }
101
+ ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sprint",
3
- "version": "0.0.134",
3
+ "version": "0.0.138",
4
4
  "description": "Create a new Sprint API project",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@ import { join } from "path";
5
5
  import color from "picocolors";
6
6
  import * as p from "@clack/prompts";
7
7
  import { validateProjectName } from "./validators.js";
8
- import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getMainFile, getHomeRoute, getAdminRoute, getHomeController, getAdminController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
8
+ import { getTypeScriptPackageJson, getJavaScriptPackageJson, getTsConfig, getMainFile, getHomeRoute, getAdminRoute, getUploadRoute, getHomeController, getAdminController, getUploadController, getEnvExample, getInternalAuthMiddleware, getUserAuthMiddleware, getHomeSchema, getAdminSchema, getUploadSchema, getDockerfile, getDockerCompose, getGitignore, getDockerIgnore, getSprintConfigFile, getEnvDevelopment, getEnvProduction, getExampleCronJob, getGraphQLFiles } from "./generators.js";
9
9
 
10
10
  type TelemetryProviders = "none" | "sentry" | "glitchtip" | "discord" | "open-telemetry" | "telegram" | "nodemailer";
11
11
 
@@ -48,7 +48,7 @@ export async function runCLI(args: string[]) {
48
48
  telemetry: options.telemetry ?? "none",
49
49
  swagger: options.swagger ?? true,
50
50
  graphql: options.graphql ?? false,
51
- docker: options.docker || false,
51
+ docker: options.docker || false
52
52
  };
53
53
  } else {
54
54
  config = await p.group(
@@ -57,7 +57,7 @@ export async function runCLI(args: string[]) {
57
57
  p.text({
58
58
  message: "Project name:",
59
59
  placeholder: "my-api",
60
- validate: (v) => validateProjectName(v || "sprint-app") || undefined,
60
+ validate: (v) => validateProjectName(v || "sprint-app") || undefined
61
61
  }),
62
62
 
63
63
  language: () =>
@@ -87,13 +87,13 @@ export async function runCLI(args: string[]) {
87
87
 
88
88
  graphql: () => p.confirm({ message: "Add GraphQL support?", initialValue: false }),
89
89
 
90
- docker: () => p.confirm({ message: "Add Docker support?", initialValue: false }),
90
+ docker: () => p.confirm({ message: "Add Docker support?", initialValue: false })
91
91
  },
92
92
  {
93
93
  onCancel: () => {
94
94
  p.cancel("Cancelled.");
95
95
  process.exit(0);
96
- },
96
+ }
97
97
  }
98
98
  );
99
99
  }
@@ -143,13 +143,7 @@ export async function runCLI(args: string[]) {
143
143
  }
144
144
 
145
145
  const cdCmd = config.projectName === "." ? "" : `cd ${config.projectName} && `;
146
- p.note(
147
- [
148
- !installDeps ? `${cdCmd}npm install --include=dev` : "",
149
- `${cdCmd}npm run dev`
150
- ].filter(Boolean).join("\n"),
151
- "Next steps"
152
- );
146
+ p.note([!installDeps ? `${cdCmd}npm install --include=dev` : "", `${cdCmd}npm run dev` ].filter(Boolean).join("\n"), "Next steps");
153
147
 
154
148
  p.outro("Ready. Happy shipping.");
155
149
  };
@@ -233,9 +227,7 @@ async function createProject(
233
227
  await mkdir(join(srcDir, "config"), { recursive: true });
234
228
  await mkdir(join(srcDir, "services"), { recursive: true });
235
229
 
236
- if (graphql) {
237
- await mkdir(join(srcDir, "graphql"), { recursive: true });
238
- }
230
+ if (graphql) await mkdir(join(srcDir, "graphql"), { recursive: true });
239
231
 
240
232
  if (language === "typescript") {
241
233
  await writeFile(join(srcDir, "config", "index.ts"), "");
@@ -251,15 +243,18 @@ async function createProject(
251
243
 
252
244
  await writeFile(join(srcDir, "routes", "home." + (language === "typescript" ? "ts" : "js")), getHomeRoute(language));
253
245
  await writeFile(join(srcDir, "routes", "admin." + (language === "typescript" ? "ts" : "js")), getAdminRoute(language));
246
+ await writeFile(join(srcDir, "routes", "upload." + (language === "typescript" ? "ts" : "js")), getUploadRoute(language));
254
247
 
255
248
  await writeFile(join(srcDir, "controllers", "home." + (language === "typescript" ? "ts" : "js")), getHomeController(language));
256
249
  await writeFile(join(srcDir, "controllers", "admin." + (language === "typescript" ? "ts" : "js")), getAdminController(language));
250
+ await writeFile(join(srcDir, "controllers", "upload." + (language === "typescript" ? "ts" : "js")), getUploadController(language));
257
251
 
258
252
  await writeFile(join(srcDir, "middlewares", "auth.internal." + (language === "typescript" ? "ts" : "js")), getInternalAuthMiddleware(language));
259
253
  await writeFile(join(srcDir, "middlewares", "auth.user." + (language === "typescript" ? "ts" : "js")), getUserAuthMiddleware(language));
260
254
 
261
255
  await writeFile(join(srcDir, "schemas", "home." + (language === "typescript" ? "ts" : "js")), getHomeSchema(language));
262
256
  await writeFile(join(srcDir, "schemas", "admin." + (language === "typescript" ? "ts" : "js")), getAdminSchema(language));
257
+ await writeFile(join(srcDir, "schemas", "upload." + (language === "typescript" ? "ts" : "js")), getUploadSchema(language));
263
258
 
264
259
  await writeFile(join(srcDir, "cronjobs", "example." + (language === "typescript" ? "ts" : "js")), getExampleCronJob(language));
265
260
 
@@ -98,4 +98,114 @@ export const jwtGenerateController = (req, res) => {
98
98
  };
99
99
  `;
100
100
  }
101
- };
101
+ };
102
+
103
+ export function getUploadController(language: string) {
104
+ if (language === "typescript") {
105
+ return `import { Handler, SprintRequest, SprintResponse } from "sprint-es";
106
+
107
+ export const uploadPdfController: Handler = (req: SprintRequest, res: SprintResponse) => {
108
+ const file = req.files?.document[0];
109
+
110
+ if (!file) return res.status(400).json({ error: "No file uploaded" });
111
+
112
+ res.json({
113
+ message: "PDF uploaded successfully",
114
+ file: {
115
+ name: file.originalname,
116
+ size: file.size,
117
+ type: file.mimetype
118
+ }
119
+ });
120
+ };
121
+
122
+ export const uploadMultiplePdfsController: Handler = (req: SprintRequest, res: SprintResponse) => {
123
+ const files = req.files?.documents || [];
124
+
125
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
126
+
127
+ res.json({
128
+ message: \`\${files.length} PDFs uploaded successfully\`,
129
+ files: files.map((f) => ({
130
+ name: f.originalname,
131
+ size: f.size,
132
+ type: f.mimetype
133
+ }))
134
+ });
135
+ };
136
+
137
+ export const streamUploadController: Handler = (req: SprintRequest, res: SprintResponse) => {
138
+ const files = (req as any).files?.file || [];
139
+
140
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
141
+
142
+ res.json({
143
+ message: \`\${files.length} file(s) processed via streaming\`,
144
+ files: files.map((f: any) => ({
145
+ fieldName: f.fieldname,
146
+ filename: f.originalname,
147
+ mimeType: f.mimetype,
148
+ encoding: f.encoding
149
+ }))
150
+ });
151
+ };
152
+ `;
153
+ }
154
+ return `export const uploadPdfController = (req, res) => {
155
+ const file = req.file;
156
+
157
+ if (!file) return res.status(400).json({ error: "No file uploaded" });
158
+
159
+ res.json({
160
+ message: "PDF uploaded successfully",
161
+ file: {
162
+ name: file.originalname,
163
+ size: file.size,
164
+ type: file.mimetype
165
+ }
166
+ });
167
+ };
168
+
169
+ export const uploadMultiplePdfsController = (req, res) => {
170
+ const files = req.files?.documents || [];
171
+
172
+ if (!files || files.length === 0) return res.status(400).json({ error: "No files uploaded" });
173
+
174
+ res.json({
175
+ message: \`\${files.length} PDFs uploaded successfully\`,
176
+ files: files.map((f) => ({
177
+ name: f.originalname,
178
+ size: f.size,
179
+ type: f.mimetype
180
+ }))
181
+ });
182
+ };
183
+
184
+ export const streamUploadController = async (req, res, next) => {
185
+ const sprint = req.sprintInstance;
186
+
187
+ if (!sprint) return res.status(500).json({ error: "Sprint instance not available" });
188
+
189
+ try {
190
+ const streamParser = sprint.streamUpload({
191
+ limits: { fileSize: 10 * 1024 * 1024 }
192
+ });
193
+
194
+ const { files, fields } = await streamParser(req, res);
195
+
196
+ res.json({
197
+ message: \`\${files.length} file(s) processed via streaming\`,
198
+ files: files.map((f) => ({
199
+ fieldName: f.fieldName,
200
+ filename: f.filename,
201
+ mimeType: f.mimeType,
202
+ encoding: f.encoding
203
+ })),
204
+ fields
205
+ });
206
+ } catch (error) {
207
+ return res.status(400).json({ error: "Stream upload failed", details: error });
208
+ }
209
+ };
210
+ `;
211
+ }
@@ -8,16 +8,16 @@ export { getTsConfig, getSprintConfigFile } from "./configFiles.js";
8
8
  export { getEnvExample, getEnvDevelopment, getEnvProduction } from "./env.js";
9
9
 
10
10
  // Routes
11
- export { getMainFile, getHomeRoute, getAdminRoute } from "./routes.js";
11
+ export { getMainFile, getHomeRoute, getAdminRoute, getUploadRoute } from "./routes.js";
12
12
 
13
13
  // Controllers
14
- export { getHomeController, getAdminController } from "./controllers.js";
14
+ export { getHomeController, getAdminController, getUploadController } from "./controllers.js";
15
15
 
16
16
  // Middlewares
17
17
  export { getInternalAuthMiddleware, getUserAuthMiddleware } from "./middlewares.js";
18
18
 
19
19
  // Schemas
20
- export { getHomeSchema, getAdminSchema } from "./schemas.js";
20
+ export { getHomeSchema, getAdminSchema, getUploadSchema } from "./schemas.js";
21
21
 
22
22
  // Cronjobs
23
23
  export { getExampleCronJob } from "./cronjobs.js";
@@ -16,7 +16,7 @@ export function generateJWTKeys(): JWTKeys {
16
16
 
17
17
  export function getTypeScriptPackageJson(name: string, telemetry: string, swagger: boolean, graphql: boolean) {
18
18
  const deps: Record<string, string> = {
19
- "sprint-es": "^0.0.156"
19
+ "sprint-es": "^0.0.168"
20
20
  };
21
21
 
22
22
  const devDeps: Record<string, string> = {
@@ -29,13 +29,16 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
29
29
  if (telemetry === "sentry" || telemetry === "glitchtip") deps["@sentry/node"] = "^8.0.0";
30
30
  else if (telemetry === "discord") deps["axios"] = "^1.6.0";
31
31
 
32
- if (swagger) deps["swagger-ui-express"] = "^5.0.0";
33
- if (swagger) devDeps["@types/swagger-ui-express"] = "^4.1.8";
32
+ if (swagger) {
33
+ deps["swagger-ui-express"] = "^5.0.0";
34
+ devDeps["@types/swagger-ui-express"] = "^4.1.8";
35
+ }
34
36
 
35
37
  if (graphql) {
36
38
  deps["graphql"] = "^16.13.0";
37
39
  deps["graphql-http"] = "^1.22.4";
38
40
  deps["ruru"] = "^2.0.0-rc.6";
41
+ devDeps["@types/swagger-ui-express"] = "^4.1.8";
39
42
  }
40
43
 
41
44
  return {
@@ -73,7 +76,7 @@ export function getTypeScriptPackageJson(name: string, telemetry: string, swagge
73
76
 
74
77
  export function getJavaScriptPackageJson(name: string, telemetry: string, swagger: boolean, graphql: boolean) {
75
78
  const deps: Record<string, string> = {
76
- "sprint-es": "^0.0.156"
79
+ "sprint-es": "^0.0.168"
77
80
  };
78
81
 
79
82
  if (telemetry === "sentry" || telemetry === "glitchtip") deps["@sentry/node"] = "^8.0.0";
@@ -83,6 +83,35 @@ router.get("/", adminSchema, adminController);
83
83
  router.get("/users", adminSchema, adminUsersController);
84
84
  router.post("/jwt/generate", jwtGenerateSchema, jwtGenerateController);
85
85
 
86
+ export default router;
87
+ `;
88
+ };
89
+
90
+ export function getUploadRoute(language: string) {
91
+ if (language === "typescript") {
92
+ return `import { Router } from "sprint-es";
93
+ import { uploadPdfSchema, uploadMultiplePdfsSchema, streamUploadSchema } from "@/schemas/upload";
94
+ import { uploadPdfController, uploadMultiplePdfsController, streamUploadController } from "@/controllers/upload";
95
+
96
+ const router = Router();
97
+
98
+ router.post("/pdf", uploadPdfSchema, uploadPdfController);
99
+ router.post("/pdfs", uploadMultiplePdfsSchema, uploadMultiplePdfsController);
100
+ router.post("/stream", streamUploadSchema, streamUploadController);
101
+
102
+ export default router;
103
+ `;
104
+ }
105
+ return `import { Router } from "sprint-es";
106
+ import { uploadPdfSchema, uploadMultiplePdfsSchema, streamUploadSchema } from "../schemas/upload.js";
107
+ import { uploadPdfController, uploadMultiplePdfsController, streamUploadController } from "../controllers/upload.js";
108
+
109
+ const router = Router();
110
+
111
+ router.post("/pdf", uploadPdfSchema, uploadPdfController);
112
+ router.post("/pdfs", uploadMultiplePdfsSchema, uploadMultiplePdfsController);
113
+ router.post("/stream", streamUploadSchema, streamUploadController);
114
+
86
115
  export default router;
87
116
  `;
88
117
  };
@@ -52,4 +52,49 @@ export const jwtGenerateSchema = defineRouteSchema({
52
52
  })
53
53
  });
54
54
  `;
55
+ };
56
+
57
+ export function getUploadSchema(language: string) {
58
+ if (language === "typescript") {
59
+ return `import { z, defineRouteSchema } from "sprint-es/schemas";
60
+
61
+ export const uploadPdfSchema = defineRouteSchema({
62
+ files: {
63
+ document: z.files.format("pdf").maxSize(10 * 1024 * 1024)
64
+ }
65
+ });
66
+
67
+ export const uploadMultiplePdfsSchema = defineRouteSchema({
68
+ files: {
69
+ documents: z.files.format("pdf").maxSize(10 * 1024 * 1024)
70
+ }
71
+ });
72
+
73
+ export const streamUploadSchema = defineRouteSchema({
74
+ files: {
75
+ file: z.files.stream().maxSize(10 * 1024 * 1024)
76
+ }
77
+ });
78
+ `;
79
+ }
80
+ return `import { z, defineRouteSchema } from "sprint-es/schemas";
81
+
82
+ export const uploadPdfSchema = defineRouteSchema({
83
+ files: {
84
+ document: z.files.format("pdf").maxSize(10 * 1024 * 1024)
85
+ }
86
+ });
87
+
88
+ export const uploadMultiplePdfsSchema = defineRouteSchema({
89
+ files: {
90
+ documents: z.files.format("pdf").maxSize(10 * 1024 * 1024)
91
+ }
92
+ });
93
+
94
+ export const streamUploadSchema = defineRouteSchema({
95
+ files: {
96
+ file: z.files.stream().maxSize(10 * 1024 * 1024)
97
+ }
98
+ });
99
+ `;
55
100
  };