sprint-es 0.0.78 → 0.0.80

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/cjs/cli.cjs CHANGED
@@ -23,6 +23,22 @@ function _interopNamespaceDefault(e) {
23
23
  const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
24
24
  const args = process.argv.slice(2);
25
25
  const command = args[0];
26
+ const pc = {
27
+ red: (s) => `\x1B[31m${s}\x1B[0m`,
28
+ yellow: (s) => `\x1B[33m${s}\x1B[0m`,
29
+ cyan: (s) => `\x1B[36m${s}\x1B[0m`,
30
+ green: (s) => `\x1B[32m${s}\x1B[0m`,
31
+ dim: (s) => `\x1B[2m${s}\x1B[0m`,
32
+ bold: (s) => `\x1B[1m${s}\x1B[0m`
33
+ };
34
+ const logger = {
35
+ error: (...args2) => console.log(pc.red(args2.join(" "))),
36
+ warn: (...args2) => console.log(pc.yellow(args2.join(" "))),
37
+ info: (...args2) => console.log(pc.cyan(args2.join(" "))),
38
+ success: (...args2) => console.log(pc.green(args2.join(" "))),
39
+ dim: (...args2) => console.log(pc.dim(args2.join(" "))),
40
+ break: () => console.log("")
41
+ };
26
42
  if (!command) {
27
43
  console.log("\nšŸš€ Sprint CLI\n");
28
44
  console.log("Usage: sprint-es <command>");
@@ -30,6 +46,7 @@ if (!command) {
30
46
  console.log(" dev Start development server");
31
47
  console.log(" build Build for production");
32
48
  console.log(" start Start production server");
49
+ console.log(" doctor Analyze routes and middlewares for missing schemas");
33
50
  console.log(" generate-keys Generate secure keys for JWT encryption");
34
51
  console.log("\nOptions:");
35
52
  console.log(" --help Show this help message");
@@ -42,6 +59,7 @@ if (command === "--help" || command === "-h") {
42
59
  console.log(" dev Start development server");
43
60
  console.log(" build Build for production");
44
61
  console.log(" start Start production server");
62
+ console.log(" doctor Analyze routes and middlewares for missing schemas");
45
63
  console.log(" generate-keys Generate secure keys for JWT encryption");
46
64
  process.exit(0);
47
65
  }
@@ -84,6 +102,199 @@ function generateJWTSecret() {
84
102
  }
85
103
  return chars.join("");
86
104
  }
105
+ function scanDirectory(dir, extensions) {
106
+ const files = [];
107
+ if (!fs.existsSync(dir)) return files;
108
+ const entries = fs.readdirSync(dir);
109
+ for (const entry of entries) {
110
+ const fullPath = path.join(dir, entry);
111
+ const stat = fs.statSync(fullPath);
112
+ if (stat.isDirectory()) {
113
+ files.push(...scanDirectory(fullPath, extensions));
114
+ } else if (stat.isFile() && extensions.some((ext) => entry.endsWith(ext))) {
115
+ files.push(fullPath);
116
+ }
117
+ }
118
+ return files;
119
+ }
120
+ function extractRoutesFromFile(filePath) {
121
+ const routes = [];
122
+ try {
123
+ const content = fs.readFileSync(filePath, "utf-8");
124
+ const lines = content.split("\n");
125
+ const routerMethods = ["get", "post", "put", "delete", "patch", "all", "head", "options"];
126
+ for (const line of lines) {
127
+ const trimmed = line.trim();
128
+ for (const method of routerMethods) {
129
+ const match = trimmed.match(new RegExp(`router\\.${method}\\s*\\(\\s*['"\`]([^'"\`]+)['"\`]`));
130
+ if (match) {
131
+ routes.push({
132
+ file: filePath,
133
+ path: match[1],
134
+ method: method.toUpperCase(),
135
+ hasSchema: false
136
+ });
137
+ break;
138
+ }
139
+ }
140
+ }
141
+ } catch {
142
+ }
143
+ return routes;
144
+ }
145
+ function checkRouteHasSchema(filePath, routePath, method) {
146
+ try {
147
+ const content = fs.readFileSync(filePath, "utf-8");
148
+ const routePattern = new RegExp(`router\\.${method.toLowerCase()}\\s*\\(\\s*['"\`]${routePath.replace("/", "\\/")}['"\`]\\s*,\\s*(\\w+)`);
149
+ const schemaVarMatch = content.match(routePattern);
150
+ if (schemaVarMatch) {
151
+ const schemaVar = schemaVarMatch[1];
152
+ const schemaDefinitionPattern = new RegExp(`export\\s+const\\s+${schemaVar}\\s*=\\s*defineRouteSchema`);
153
+ if (schemaDefinitionPattern.test(content)) {
154
+ return true;
155
+ }
156
+ }
157
+ const directSchemaPattern = new RegExp(`router\\.${method.toLowerCase()}\\s*\\(\\s*['"\`]${routePath.replace("/", "\\/")}['"\`]\\s*,\\s*defineRouteSchema`);
158
+ if (directSchemaPattern.test(content)) {
159
+ return true;
160
+ }
161
+ return false;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+ function hasSchemaInMiddleware(filePath) {
167
+ try {
168
+ const content = fs.readFileSync(filePath, "utf-8");
169
+ if (content.includes("schema:") || content.includes("__sprintMiddlewareSchema")) {
170
+ return true;
171
+ }
172
+ return false;
173
+ } catch {
174
+ return false;
175
+ }
176
+ }
177
+ function extractMiddlewareName(filePath) {
178
+ try {
179
+ const content = fs.readFileSync(filePath, "utf-8");
180
+ const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
181
+ if (nameMatch) {
182
+ return nameMatch[1];
183
+ }
184
+ const fileName = filePath.split(/[/\\]/).pop() || filePath;
185
+ return fileName.replace(/\.(ts|js)$/, "");
186
+ } catch {
187
+ return filePath;
188
+ }
189
+ }
190
+ function renderFramedBox(lines, title) {
191
+ if (lines.length === 0) return;
192
+ const maxLength = Math.max(...lines.map((line) => line.length));
193
+ const horizontalPadding = 1;
194
+ const borderLine = "─".repeat(maxLength + horizontalPadding * 2);
195
+ console.log(pc.dim(`ā”Œ${borderLine}┐`));
196
+ if (title) {
197
+ const titlePadding = " ".repeat(maxLength - title.length + horizontalPadding * 2);
198
+ console.log(pc.dim("│") + " " + pc.bold(pc.cyan(title)) + titlePadding + pc.dim("│"));
199
+ console.log(pc.dim(`ā”œ${borderLine}┤`));
200
+ }
201
+ for (const line of lines) {
202
+ const padding = " ".repeat(maxLength - line.length + horizontalPadding * 2);
203
+ console.log(pc.dim("│") + " " + line + padding + pc.dim("│"));
204
+ }
205
+ console.log(pc.dim(`ā””${borderLine}ā”˜`));
206
+ }
207
+ async function runDoctor() {
208
+ logger.break();
209
+ logger.info("šŸ” Sprint Doctor - Analyzing routes and middlewares...\n");
210
+ const routesPath = path.join(projectRoot, "src/routes");
211
+ const middlewaresPath = path.join(projectRoot, "src/middlewares");
212
+ const routeFiles = scanDirectory(routesPath, [".ts", ".js"]);
213
+ const middlewareFiles = scanDirectory(middlewaresPath, [".ts", ".js"]);
214
+ const allRoutes = [];
215
+ for (const file of routeFiles) {
216
+ const routes = extractRoutesFromFile(file);
217
+ for (const route of routes) {
218
+ route.hasSchema = checkRouteHasSchema(file, route.path, route.method);
219
+ allRoutes.push(route);
220
+ }
221
+ }
222
+ const middlewares = [];
223
+ for (const file of middlewareFiles) {
224
+ middlewares.push({
225
+ file,
226
+ name: extractMiddlewareName(file),
227
+ hasSchema: hasSchemaInMiddleware(file)
228
+ });
229
+ }
230
+ const routesWithoutSchema = allRoutes.filter((r) => !r.hasSchema);
231
+ const middlewaresWithoutSchema = middlewares.filter((m) => !m.hasSchema);
232
+ const routesWithSchema = allRoutes.filter((r) => r.hasSchema);
233
+ const middlewaresWithSchema = middlewares.filter((m) => m.hasSchema);
234
+ logger.break();
235
+ console.log(pc.bold("šŸ“Š Schema Coverage Report\n"));
236
+ const routesLines = [
237
+ `${pc.green("āœ“")} Routes with schema: ${routesWithSchema.length}`,
238
+ `${routesWithoutSchema.length > 0 ? pc.red("āœ—") : pc.green("āœ“")} Routes without schema: ${routesWithoutSchema.length}`,
239
+ `${pc.dim("─".repeat(40))}`,
240
+ `Total routes: ${allRoutes.length}`
241
+ ];
242
+ renderFramedBox(routesLines, "Routes");
243
+ logger.break();
244
+ const middlewareLines = [
245
+ `${pc.green("āœ“")} Middlewares with schema: ${middlewaresWithSchema.length}`,
246
+ `${middlewaresWithoutSchema.length > 0 ? pc.red("āœ—") : pc.green("āœ“")} Middlewares without schema: ${middlewaresWithoutSchema.length}`,
247
+ `${pc.dim("─".repeat(40))}`,
248
+ `Total middlewares: ${middlewares.length}`
249
+ ];
250
+ renderFramedBox(middlewareLines, "Middlewares");
251
+ logger.break();
252
+ if (routesWithoutSchema.length > 0) {
253
+ console.log(pc.bold(pc.yellow("āš ļø Routes without schema:")));
254
+ logger.break();
255
+ const uniqueRoutes = routesWithoutSchema.reduce((acc, route) => {
256
+ const key = `${route.method}:${route.path}`;
257
+ if (!acc[key]) acc[key] = { ...route, files: [route.file] };
258
+ else if (!acc[key].files.includes(route.file)) acc[key].files.push(route.file);
259
+ return acc;
260
+ }, {});
261
+ for (const route of Object.values(uniqueRoutes)) {
262
+ const fileName = route.file.split(/[/\\]/).pop();
263
+ console.log(` ${pc.red("āœ—")} ${pc.bold(route.method)} ${route.path}`);
264
+ console.log(` ${pc.dim("File:")} ${fileName}`);
265
+ }
266
+ logger.break();
267
+ }
268
+ if (middlewaresWithoutSchema.length > 0) {
269
+ console.log(pc.bold(pc.yellow("āš ļø Middlewares without schema:")));
270
+ logger.break();
271
+ for (const mw of middlewaresWithoutSchema) {
272
+ const fileName = mw.file.split(/[/\\]/).pop();
273
+ console.log(` ${pc.red("āœ—")} ${pc.bold(mw.name)}`);
274
+ console.log(` ${pc.dim("File:")} ${fileName}`);
275
+ }
276
+ logger.break();
277
+ }
278
+ if (routesWithoutSchema.length === 0 && middlewaresWithoutSchema.length === 0) {
279
+ console.log(pc.green(pc.bold("āœ… All routes and middlewares have schemas defined!")));
280
+ logger.break();
281
+ }
282
+ const totalWithoutSchema = routesWithoutSchema.length + middlewaresWithoutSchema.length;
283
+ const totalItems = allRoutes.length + middlewares.length;
284
+ if (totalItems > 0) {
285
+ const coverage = Math.round((totalItems - totalWithoutSchema) / totalItems * 100);
286
+ console.log(pc.bold("šŸ“ˆ Schema Coverage: ") + (coverage >= 80 ? pc.green(`${coverage}%`) : coverage >= 50 ? pc.yellow(`${coverage}%`) : pc.red(`${coverage}%`)));
287
+ if (coverage < 80) {
288
+ logger.break();
289
+ console.log(pc.yellow("šŸ’” Tip: Adding schemas helps with:"));
290
+ console.log(pc.dim(" • Request validation (body, query, params, headers)"));
291
+ console.log(pc.dim(" • OpenAPI/Swagger UI auto-generation"));
292
+ console.log(pc.dim(" • Better security through input validation"));
293
+ console.log(pc.dim(" • Auto-completion in IDEs"));
294
+ }
295
+ }
296
+ logger.break();
297
+ }
87
298
  switch (command) {
88
299
  case "dev":
89
300
  console.log("šŸš€ Starting development server with hot reload...");
@@ -103,6 +314,9 @@ switch (command) {
103
314
  console.log("šŸš€ Starting production server...");
104
315
  runCommand("node dist/index.js", { NODE_ENV: "production" });
105
316
  break;
317
+ case "doctor":
318
+ runDoctor();
319
+ break;
106
320
  case "generate-keys":
107
321
  const { publicKey, privateKey } = crypto__namespace.generateKeyPairSync("rsa", {
108
322
  modulusLength: 2048,
@@ -341,19 +341,18 @@ class Sprint {
341
341
  const route = layer.route;
342
342
  for (const routeLayer of route.stack) {
343
343
  const handlers = Array.isArray(routeLayer.handle) ? routeLayer.handle : [routeLayer.handle];
344
+ let schema;
344
345
  for (const handler of handlers) {
345
- const schema = handler.__sprintRouteSchema;
346
- if (schema) {
347
- const method = (routeLayer.method || "").toUpperCase();
348
- if (method) {
349
- this.registeredRoutes.push({
350
- method,
351
- path: finalRoute + route.path,
352
- schema
353
- });
354
- }
355
- break;
356
- }
346
+ schema = handler.__sprintRouteSchema;
347
+ if (schema) break;
348
+ }
349
+ const method = (routeLayer.method || "").toUpperCase();
350
+ if (method) {
351
+ this.registeredRoutes.push({
352
+ method,
353
+ path: finalRoute + route.path,
354
+ schema
355
+ });
357
356
  }
358
357
  }
359
358
  }
@@ -472,6 +471,37 @@ class Sprint {
472
471
  console.warn("[Sprint] Failed to convert headers schema:", e);
473
472
  }
474
473
  }
474
+ if (route.schema?.sprint?.authorization) {
475
+ const authSchema = route.schema.sprint.authorization;
476
+ const description = authSchema._def?.description;
477
+ let sources = ["query:token", "headers:authorization"];
478
+ if (description) {
479
+ try {
480
+ const parsed = JSON.parse(description);
481
+ if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
482
+ } catch {
483
+ }
484
+ }
485
+ const isRequired = sources.length === 1;
486
+ for (const source of sources) {
487
+ const [type, key] = source.split(":");
488
+ if (type === "query") {
489
+ allParams.push({
490
+ name: key,
491
+ in: "query",
492
+ required: isRequired,
493
+ schema: { type: "string" }
494
+ });
495
+ } else if (type === "headers") {
496
+ allParams.push({
497
+ name: key,
498
+ in: "header",
499
+ required: isRequired,
500
+ schema: { type: "string" }
501
+ });
502
+ }
503
+ }
504
+ }
475
505
  if (this.openapi.generateOnBuild) {
476
506
  try {
477
507
  const routeMiddlewares = this.getMiddlewaresForRoute(route.path);
@@ -497,26 +527,25 @@ class Sprint {
497
527
  if (description) {
498
528
  try {
499
529
  const parsed = JSON.parse(description);
500
- if (parsed.__sprintAuthorization && parsed.sources) {
501
- sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
502
- }
530
+ if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
503
531
  } catch {
504
532
  }
505
533
  }
534
+ const isRequired = sources.length === 1;
506
535
  for (const source of sources) {
507
536
  const [type, key] = source.split(":");
508
537
  if (type === "query") {
509
538
  allParams.push({
510
539
  name: key,
511
540
  in: "query",
512
- required: true,
541
+ required: isRequired,
513
542
  schema: { type: "string" }
514
543
  });
515
544
  } else if (type === "headers") {
516
545
  allParams.push({
517
546
  name: key,
518
547
  in: "header",
519
- required: true,
548
+ required: isRequired,
520
549
  schema: { type: "string" }
521
550
  });
522
551
  }
@@ -529,9 +558,7 @@ class Sprint {
529
558
  }
530
559
  }
531
560
  if (allParams.length > 0) {
532
- const uniqueParams = allParams.filter(
533
- (param, index, self) => index === self.findIndex((p) => p.name === param.name && p.in === param.in)
534
- );
561
+ const uniqueParams = allParams.filter((param, index, self) => index === self.findIndex((p) => p.name === param.name && p.in === param.in));
535
562
  routeSpec.parameters = uniqueParams;
536
563
  }
537
564
  paths[route.path][method] = routeSpec;
@@ -556,25 +583,15 @@ class Sprint {
556
583
  const zodDef = value._def;
557
584
  const typeName = zodDef?.typeName;
558
585
  let propSchema = {};
559
- if (typeName === "ZodString") {
560
- propSchema = { type: "string" };
561
- } else if (typeName === "ZodNumber") {
562
- propSchema = { type: "number" };
563
- } else if (typeName === "ZodBoolean") {
564
- propSchema = { type: "boolean" };
565
- } else if (typeName === "ZodArray") {
566
- propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
567
- } else if (typeName === "ZodObject") {
568
- propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
569
- } else if (typeName === "ZodOptional") {
570
- continue;
571
- } else {
572
- propSchema = { type: "string" };
573
- }
586
+ if (typeName === "ZodString") propSchema = { type: "string" };
587
+ else if (typeName === "ZodNumber") propSchema = { type: "number" };
588
+ else if (typeName === "ZodBoolean") propSchema = { type: "boolean" };
589
+ else if (typeName === "ZodArray") propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
590
+ else if (typeName === "ZodObject") propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
591
+ else if (typeName === "ZodOptional") continue;
592
+ else propSchema = { type: "string" };
574
593
  properties[key] = propSchema;
575
- if (!zodDef?.isOptional && typeName !== "ZodOptional") {
576
- required.push(key);
577
- }
594
+ if (!zodDef?.isOptional && typeName !== "ZodOptional") required.push(key);
578
595
  }
579
596
  return { type: "object", properties, required: required.length > 0 ? required : void 0 };
580
597
  }
@@ -589,15 +606,10 @@ class Sprint {
589
606
  const zodDef = value._def;
590
607
  const typeName = zodDef?.typeName;
591
608
  let paramSchema = {};
592
- if (typeName === "ZodString") {
593
- paramSchema = { type: "string" };
594
- } else if (typeName === "ZodNumber") {
595
- paramSchema = { type: "number" };
596
- } else if (typeName === "ZodBoolean") {
597
- paramSchema = { type: "boolean" };
598
- } else {
599
- paramSchema = { type: "string" };
600
- }
609
+ if (typeName === "ZodString") paramSchema = { type: "string" };
610
+ else if (typeName === "ZodNumber") paramSchema = { type: "number" };
611
+ else if (typeName === "ZodBoolean") paramSchema = { type: "boolean" };
612
+ else paramSchema = { type: "string" };
601
613
  params.push({
602
614
  name: key,
603
615
  in: "query",
@@ -616,15 +628,10 @@ class Sprint {
616
628
  const zodDef = value._def;
617
629
  const typeName = zodDef?.typeName;
618
630
  let paramSchema = {};
619
- if (typeName === "ZodString") {
620
- paramSchema = { type: "string" };
621
- } else if (typeName === "ZodNumber") {
622
- paramSchema = { type: "number" };
623
- } else if (typeName === "ZodBoolean") {
624
- paramSchema = { type: "boolean" };
625
- } else {
626
- paramSchema = { type: "string" };
627
- }
631
+ if (typeName === "ZodString") paramSchema = { type: "string" };
632
+ else if (typeName === "ZodNumber") paramSchema = { type: "number" };
633
+ else if (typeName === "ZodBoolean") paramSchema = { type: "boolean" };
634
+ else paramSchema = { type: "string" };
628
635
  headers.push({
629
636
  name: key,
630
637
  in: "header",
@@ -713,7 +720,9 @@ class Sprint {
713
720
  function createSchemaValidationMiddleware(schema) {
714
721
  return (req, res, next) => {
715
722
  const errors = [];
716
- if (schema.body) {
723
+ const method = req.method.toUpperCase();
724
+ const noBodyMethods = ["GET", "HEAD", "DELETE"];
725
+ if (schema.body && !noBodyMethods.includes(method)) {
717
726
  const result = schema.body.safeParse(req.body);
718
727
  if (!result.success) {
719
728
  errors.push(...result.error.issues.map((issue) => ({
@@ -38,7 +38,9 @@ function parseSchema(schema, data) {
38
38
  function defineRouteSchema(schema) {
39
39
  const middleware = (req, res, next) => {
40
40
  const errors = [];
41
- if (schema.body) {
41
+ const method = req.method.toUpperCase();
42
+ const noBodyMethods = ["GET", "HEAD", "DELETE"];
43
+ if (schema.body && !noBodyMethods.includes(method)) {
42
44
  const result = parseSchema(schema.body, req.body);
43
45
  if (!result.success) errors.push(...result.errors.map((e) => ({ location: "body", ...e })));
44
46
  }
package/dist/esm/cli.js CHANGED
@@ -1,10 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync } from "fs";
2
+ import { existsSync, readdirSync, statSync, readFileSync } from "fs";
3
3
  import * as crypto from "crypto";
4
4
  import { join, resolve } from "path";
5
5
  import { spawn } from "child_process";
6
6
  const args = process.argv.slice(2);
7
7
  const command = args[0];
8
+ const pc = {
9
+ red: (s) => `\x1B[31m${s}\x1B[0m`,
10
+ yellow: (s) => `\x1B[33m${s}\x1B[0m`,
11
+ cyan: (s) => `\x1B[36m${s}\x1B[0m`,
12
+ green: (s) => `\x1B[32m${s}\x1B[0m`,
13
+ dim: (s) => `\x1B[2m${s}\x1B[0m`,
14
+ bold: (s) => `\x1B[1m${s}\x1B[0m`
15
+ };
16
+ const logger = {
17
+ error: (...args2) => console.log(pc.red(args2.join(" "))),
18
+ warn: (...args2) => console.log(pc.yellow(args2.join(" "))),
19
+ info: (...args2) => console.log(pc.cyan(args2.join(" "))),
20
+ success: (...args2) => console.log(pc.green(args2.join(" "))),
21
+ dim: (...args2) => console.log(pc.dim(args2.join(" "))),
22
+ break: () => console.log("")
23
+ };
8
24
  if (!command) {
9
25
  console.log("\nšŸš€ Sprint CLI\n");
10
26
  console.log("Usage: sprint-es <command>");
@@ -12,6 +28,7 @@ if (!command) {
12
28
  console.log(" dev Start development server");
13
29
  console.log(" build Build for production");
14
30
  console.log(" start Start production server");
31
+ console.log(" doctor Analyze routes and middlewares for missing schemas");
15
32
  console.log(" generate-keys Generate secure keys for JWT encryption");
16
33
  console.log("\nOptions:");
17
34
  console.log(" --help Show this help message");
@@ -24,6 +41,7 @@ if (command === "--help" || command === "-h") {
24
41
  console.log(" dev Start development server");
25
42
  console.log(" build Build for production");
26
43
  console.log(" start Start production server");
44
+ console.log(" doctor Analyze routes and middlewares for missing schemas");
27
45
  console.log(" generate-keys Generate secure keys for JWT encryption");
28
46
  process.exit(0);
29
47
  }
@@ -66,6 +84,199 @@ function generateJWTSecret() {
66
84
  }
67
85
  return chars.join("");
68
86
  }
87
+ function scanDirectory(dir, extensions) {
88
+ const files = [];
89
+ if (!existsSync(dir)) return files;
90
+ const entries = readdirSync(dir);
91
+ for (const entry of entries) {
92
+ const fullPath = join(dir, entry);
93
+ const stat = statSync(fullPath);
94
+ if (stat.isDirectory()) {
95
+ files.push(...scanDirectory(fullPath, extensions));
96
+ } else if (stat.isFile() && extensions.some((ext) => entry.endsWith(ext))) {
97
+ files.push(fullPath);
98
+ }
99
+ }
100
+ return files;
101
+ }
102
+ function extractRoutesFromFile(filePath) {
103
+ const routes = [];
104
+ try {
105
+ const content = readFileSync(filePath, "utf-8");
106
+ const lines = content.split("\n");
107
+ const routerMethods = ["get", "post", "put", "delete", "patch", "all", "head", "options"];
108
+ for (const line of lines) {
109
+ const trimmed = line.trim();
110
+ for (const method of routerMethods) {
111
+ const match = trimmed.match(new RegExp(`router\\.${method}\\s*\\(\\s*['"\`]([^'"\`]+)['"\`]`));
112
+ if (match) {
113
+ routes.push({
114
+ file: filePath,
115
+ path: match[1],
116
+ method: method.toUpperCase(),
117
+ hasSchema: false
118
+ });
119
+ break;
120
+ }
121
+ }
122
+ }
123
+ } catch {
124
+ }
125
+ return routes;
126
+ }
127
+ function checkRouteHasSchema(filePath, routePath, method) {
128
+ try {
129
+ const content = readFileSync(filePath, "utf-8");
130
+ const routePattern = new RegExp(`router\\.${method.toLowerCase()}\\s*\\(\\s*['"\`]${routePath.replace("/", "\\/")}['"\`]\\s*,\\s*(\\w+)`);
131
+ const schemaVarMatch = content.match(routePattern);
132
+ if (schemaVarMatch) {
133
+ const schemaVar = schemaVarMatch[1];
134
+ const schemaDefinitionPattern = new RegExp(`export\\s+const\\s+${schemaVar}\\s*=\\s*defineRouteSchema`);
135
+ if (schemaDefinitionPattern.test(content)) {
136
+ return true;
137
+ }
138
+ }
139
+ const directSchemaPattern = new RegExp(`router\\.${method.toLowerCase()}\\s*\\(\\s*['"\`]${routePath.replace("/", "\\/")}['"\`]\\s*,\\s*defineRouteSchema`);
140
+ if (directSchemaPattern.test(content)) {
141
+ return true;
142
+ }
143
+ return false;
144
+ } catch {
145
+ return false;
146
+ }
147
+ }
148
+ function hasSchemaInMiddleware(filePath) {
149
+ try {
150
+ const content = readFileSync(filePath, "utf-8");
151
+ if (content.includes("schema:") || content.includes("__sprintMiddlewareSchema")) {
152
+ return true;
153
+ }
154
+ return false;
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+ function extractMiddlewareName(filePath) {
160
+ try {
161
+ const content = readFileSync(filePath, "utf-8");
162
+ const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
163
+ if (nameMatch) {
164
+ return nameMatch[1];
165
+ }
166
+ const fileName = filePath.split(/[/\\]/).pop() || filePath;
167
+ return fileName.replace(/\.(ts|js)$/, "");
168
+ } catch {
169
+ return filePath;
170
+ }
171
+ }
172
+ function renderFramedBox(lines, title) {
173
+ if (lines.length === 0) return;
174
+ const maxLength = Math.max(...lines.map((line) => line.length));
175
+ const horizontalPadding = 1;
176
+ const borderLine = "─".repeat(maxLength + horizontalPadding * 2);
177
+ console.log(pc.dim(`ā”Œ${borderLine}┐`));
178
+ if (title) {
179
+ const titlePadding = " ".repeat(maxLength - title.length + horizontalPadding * 2);
180
+ console.log(pc.dim("│") + " " + pc.bold(pc.cyan(title)) + titlePadding + pc.dim("│"));
181
+ console.log(pc.dim(`ā”œ${borderLine}┤`));
182
+ }
183
+ for (const line of lines) {
184
+ const padding = " ".repeat(maxLength - line.length + horizontalPadding * 2);
185
+ console.log(pc.dim("│") + " " + line + padding + pc.dim("│"));
186
+ }
187
+ console.log(pc.dim(`ā””${borderLine}ā”˜`));
188
+ }
189
+ async function runDoctor() {
190
+ logger.break();
191
+ logger.info("šŸ” Sprint Doctor - Analyzing routes and middlewares...\n");
192
+ const routesPath = join(projectRoot, "src/routes");
193
+ const middlewaresPath = join(projectRoot, "src/middlewares");
194
+ const routeFiles = scanDirectory(routesPath, [".ts", ".js"]);
195
+ const middlewareFiles = scanDirectory(middlewaresPath, [".ts", ".js"]);
196
+ const allRoutes = [];
197
+ for (const file of routeFiles) {
198
+ const routes = extractRoutesFromFile(file);
199
+ for (const route of routes) {
200
+ route.hasSchema = checkRouteHasSchema(file, route.path, route.method);
201
+ allRoutes.push(route);
202
+ }
203
+ }
204
+ const middlewares = [];
205
+ for (const file of middlewareFiles) {
206
+ middlewares.push({
207
+ file,
208
+ name: extractMiddlewareName(file),
209
+ hasSchema: hasSchemaInMiddleware(file)
210
+ });
211
+ }
212
+ const routesWithoutSchema = allRoutes.filter((r) => !r.hasSchema);
213
+ const middlewaresWithoutSchema = middlewares.filter((m) => !m.hasSchema);
214
+ const routesWithSchema = allRoutes.filter((r) => r.hasSchema);
215
+ const middlewaresWithSchema = middlewares.filter((m) => m.hasSchema);
216
+ logger.break();
217
+ console.log(pc.bold("šŸ“Š Schema Coverage Report\n"));
218
+ const routesLines = [
219
+ `${pc.green("āœ“")} Routes with schema: ${routesWithSchema.length}`,
220
+ `${routesWithoutSchema.length > 0 ? pc.red("āœ—") : pc.green("āœ“")} Routes without schema: ${routesWithoutSchema.length}`,
221
+ `${pc.dim("─".repeat(40))}`,
222
+ `Total routes: ${allRoutes.length}`
223
+ ];
224
+ renderFramedBox(routesLines, "Routes");
225
+ logger.break();
226
+ const middlewareLines = [
227
+ `${pc.green("āœ“")} Middlewares with schema: ${middlewaresWithSchema.length}`,
228
+ `${middlewaresWithoutSchema.length > 0 ? pc.red("āœ—") : pc.green("āœ“")} Middlewares without schema: ${middlewaresWithoutSchema.length}`,
229
+ `${pc.dim("─".repeat(40))}`,
230
+ `Total middlewares: ${middlewares.length}`
231
+ ];
232
+ renderFramedBox(middlewareLines, "Middlewares");
233
+ logger.break();
234
+ if (routesWithoutSchema.length > 0) {
235
+ console.log(pc.bold(pc.yellow("āš ļø Routes without schema:")));
236
+ logger.break();
237
+ const uniqueRoutes = routesWithoutSchema.reduce((acc, route) => {
238
+ const key = `${route.method}:${route.path}`;
239
+ if (!acc[key]) acc[key] = { ...route, files: [route.file] };
240
+ else if (!acc[key].files.includes(route.file)) acc[key].files.push(route.file);
241
+ return acc;
242
+ }, {});
243
+ for (const route of Object.values(uniqueRoutes)) {
244
+ const fileName = route.file.split(/[/\\]/).pop();
245
+ console.log(` ${pc.red("āœ—")} ${pc.bold(route.method)} ${route.path}`);
246
+ console.log(` ${pc.dim("File:")} ${fileName}`);
247
+ }
248
+ logger.break();
249
+ }
250
+ if (middlewaresWithoutSchema.length > 0) {
251
+ console.log(pc.bold(pc.yellow("āš ļø Middlewares without schema:")));
252
+ logger.break();
253
+ for (const mw of middlewaresWithoutSchema) {
254
+ const fileName = mw.file.split(/[/\\]/).pop();
255
+ console.log(` ${pc.red("āœ—")} ${pc.bold(mw.name)}`);
256
+ console.log(` ${pc.dim("File:")} ${fileName}`);
257
+ }
258
+ logger.break();
259
+ }
260
+ if (routesWithoutSchema.length === 0 && middlewaresWithoutSchema.length === 0) {
261
+ console.log(pc.green(pc.bold("āœ… All routes and middlewares have schemas defined!")));
262
+ logger.break();
263
+ }
264
+ const totalWithoutSchema = routesWithoutSchema.length + middlewaresWithoutSchema.length;
265
+ const totalItems = allRoutes.length + middlewares.length;
266
+ if (totalItems > 0) {
267
+ const coverage = Math.round((totalItems - totalWithoutSchema) / totalItems * 100);
268
+ console.log(pc.bold("šŸ“ˆ Schema Coverage: ") + (coverage >= 80 ? pc.green(`${coverage}%`) : coverage >= 50 ? pc.yellow(`${coverage}%`) : pc.red(`${coverage}%`)));
269
+ if (coverage < 80) {
270
+ logger.break();
271
+ console.log(pc.yellow("šŸ’” Tip: Adding schemas helps with:"));
272
+ console.log(pc.dim(" • Request validation (body, query, params, headers)"));
273
+ console.log(pc.dim(" • OpenAPI/Swagger UI auto-generation"));
274
+ console.log(pc.dim(" • Better security through input validation"));
275
+ console.log(pc.dim(" • Auto-completion in IDEs"));
276
+ }
277
+ }
278
+ logger.break();
279
+ }
69
280
  switch (command) {
70
281
  case "dev":
71
282
  console.log("šŸš€ Starting development server with hot reload...");
@@ -85,6 +296,9 @@ switch (command) {
85
296
  console.log("šŸš€ Starting production server...");
86
297
  runCommand("node dist/index.js", { NODE_ENV: "production" });
87
298
  break;
299
+ case "doctor":
300
+ runDoctor();
301
+ break;
88
302
  case "generate-keys":
89
303
  const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
90
304
  modulusLength: 2048,
package/dist/esm/index.js CHANGED
@@ -316,19 +316,18 @@ class Sprint {
316
316
  const route = layer.route;
317
317
  for (const routeLayer of route.stack) {
318
318
  const handlers = Array.isArray(routeLayer.handle) ? routeLayer.handle : [routeLayer.handle];
319
+ let schema;
319
320
  for (const handler of handlers) {
320
- const schema = handler.__sprintRouteSchema;
321
- if (schema) {
322
- const method = (routeLayer.method || "").toUpperCase();
323
- if (method) {
324
- this.registeredRoutes.push({
325
- method,
326
- path: finalRoute + route.path,
327
- schema
328
- });
329
- }
330
- break;
331
- }
321
+ schema = handler.__sprintRouteSchema;
322
+ if (schema) break;
323
+ }
324
+ const method = (routeLayer.method || "").toUpperCase();
325
+ if (method) {
326
+ this.registeredRoutes.push({
327
+ method,
328
+ path: finalRoute + route.path,
329
+ schema
330
+ });
332
331
  }
333
332
  }
334
333
  }
@@ -447,6 +446,37 @@ class Sprint {
447
446
  console.warn("[Sprint] Failed to convert headers schema:", e);
448
447
  }
449
448
  }
449
+ if (route.schema?.sprint?.authorization) {
450
+ const authSchema = route.schema.sprint.authorization;
451
+ const description = authSchema._def?.description;
452
+ let sources = ["query:token", "headers:authorization"];
453
+ if (description) {
454
+ try {
455
+ const parsed = JSON.parse(description);
456
+ if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
457
+ } catch {
458
+ }
459
+ }
460
+ const isRequired = sources.length === 1;
461
+ for (const source of sources) {
462
+ const [type, key] = source.split(":");
463
+ if (type === "query") {
464
+ allParams.push({
465
+ name: key,
466
+ in: "query",
467
+ required: isRequired,
468
+ schema: { type: "string" }
469
+ });
470
+ } else if (type === "headers") {
471
+ allParams.push({
472
+ name: key,
473
+ in: "header",
474
+ required: isRequired,
475
+ schema: { type: "string" }
476
+ });
477
+ }
478
+ }
479
+ }
450
480
  if (this.openapi.generateOnBuild) {
451
481
  try {
452
482
  const routeMiddlewares = this.getMiddlewaresForRoute(route.path);
@@ -472,26 +502,25 @@ class Sprint {
472
502
  if (description) {
473
503
  try {
474
504
  const parsed = JSON.parse(description);
475
- if (parsed.__sprintAuthorization && parsed.sources) {
476
- sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
477
- }
505
+ if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
478
506
  } catch {
479
507
  }
480
508
  }
509
+ const isRequired = sources.length === 1;
481
510
  for (const source of sources) {
482
511
  const [type, key] = source.split(":");
483
512
  if (type === "query") {
484
513
  allParams.push({
485
514
  name: key,
486
515
  in: "query",
487
- required: true,
516
+ required: isRequired,
488
517
  schema: { type: "string" }
489
518
  });
490
519
  } else if (type === "headers") {
491
520
  allParams.push({
492
521
  name: key,
493
522
  in: "header",
494
- required: true,
523
+ required: isRequired,
495
524
  schema: { type: "string" }
496
525
  });
497
526
  }
@@ -504,9 +533,7 @@ class Sprint {
504
533
  }
505
534
  }
506
535
  if (allParams.length > 0) {
507
- const uniqueParams = allParams.filter(
508
- (param, index, self) => index === self.findIndex((p) => p.name === param.name && p.in === param.in)
509
- );
536
+ const uniqueParams = allParams.filter((param, index, self) => index === self.findIndex((p) => p.name === param.name && p.in === param.in));
510
537
  routeSpec.parameters = uniqueParams;
511
538
  }
512
539
  paths[route.path][method] = routeSpec;
@@ -531,25 +558,15 @@ class Sprint {
531
558
  const zodDef = value._def;
532
559
  const typeName = zodDef?.typeName;
533
560
  let propSchema = {};
534
- if (typeName === "ZodString") {
535
- propSchema = { type: "string" };
536
- } else if (typeName === "ZodNumber") {
537
- propSchema = { type: "number" };
538
- } else if (typeName === "ZodBoolean") {
539
- propSchema = { type: "boolean" };
540
- } else if (typeName === "ZodArray") {
541
- propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
542
- } else if (typeName === "ZodObject") {
543
- propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
544
- } else if (typeName === "ZodOptional") {
545
- continue;
546
- } else {
547
- propSchema = { type: "string" };
548
- }
561
+ if (typeName === "ZodString") propSchema = { type: "string" };
562
+ else if (typeName === "ZodNumber") propSchema = { type: "number" };
563
+ else if (typeName === "ZodBoolean") propSchema = { type: "boolean" };
564
+ else if (typeName === "ZodArray") propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
565
+ else if (typeName === "ZodObject") propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
566
+ else if (typeName === "ZodOptional") continue;
567
+ else propSchema = { type: "string" };
549
568
  properties[key] = propSchema;
550
- if (!zodDef?.isOptional && typeName !== "ZodOptional") {
551
- required.push(key);
552
- }
569
+ if (!zodDef?.isOptional && typeName !== "ZodOptional") required.push(key);
553
570
  }
554
571
  return { type: "object", properties, required: required.length > 0 ? required : void 0 };
555
572
  }
@@ -564,15 +581,10 @@ class Sprint {
564
581
  const zodDef = value._def;
565
582
  const typeName = zodDef?.typeName;
566
583
  let paramSchema = {};
567
- if (typeName === "ZodString") {
568
- paramSchema = { type: "string" };
569
- } else if (typeName === "ZodNumber") {
570
- paramSchema = { type: "number" };
571
- } else if (typeName === "ZodBoolean") {
572
- paramSchema = { type: "boolean" };
573
- } else {
574
- paramSchema = { type: "string" };
575
- }
584
+ if (typeName === "ZodString") paramSchema = { type: "string" };
585
+ else if (typeName === "ZodNumber") paramSchema = { type: "number" };
586
+ else if (typeName === "ZodBoolean") paramSchema = { type: "boolean" };
587
+ else paramSchema = { type: "string" };
576
588
  params.push({
577
589
  name: key,
578
590
  in: "query",
@@ -591,15 +603,10 @@ class Sprint {
591
603
  const zodDef = value._def;
592
604
  const typeName = zodDef?.typeName;
593
605
  let paramSchema = {};
594
- if (typeName === "ZodString") {
595
- paramSchema = { type: "string" };
596
- } else if (typeName === "ZodNumber") {
597
- paramSchema = { type: "number" };
598
- } else if (typeName === "ZodBoolean") {
599
- paramSchema = { type: "boolean" };
600
- } else {
601
- paramSchema = { type: "string" };
602
- }
606
+ if (typeName === "ZodString") paramSchema = { type: "string" };
607
+ else if (typeName === "ZodNumber") paramSchema = { type: "number" };
608
+ else if (typeName === "ZodBoolean") paramSchema = { type: "boolean" };
609
+ else paramSchema = { type: "string" };
603
610
  headers.push({
604
611
  name: key,
605
612
  in: "header",
@@ -688,7 +695,9 @@ class Sprint {
688
695
  function createSchemaValidationMiddleware(schema) {
689
696
  return (req, res, next) => {
690
697
  const errors = [];
691
- if (schema.body) {
698
+ const method = req.method.toUpperCase();
699
+ const noBodyMethods = ["GET", "HEAD", "DELETE"];
700
+ if (schema.body && !noBodyMethods.includes(method)) {
692
701
  const result = schema.body.safeParse(req.body);
693
702
  if (!result.success) {
694
703
  errors.push(...result.error.issues.map((issue) => ({
@@ -36,7 +36,9 @@ function parseSchema(schema, data) {
36
36
  function defineRouteSchema(schema) {
37
37
  const middleware = (req, res, next) => {
38
38
  const errors = [];
39
- if (schema.body) {
39
+ const method = req.method.toUpperCase();
40
+ const noBodyMethods = ["GET", "HEAD", "DELETE"];
41
+ if (schema.body && !noBodyMethods.includes(method)) {
40
42
  const result = parseSchema(schema.body, req.body);
41
43
  if (!result.success) errors.push(...result.errors.map((e) => ({ location: "body", ...e })));
42
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAyC,MAAM,SAAS,CAAC;AA6FlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CA+B3E"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAyC,MAAM,SAAS,CAAC;AA+FlF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CA+B3E"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,aAAa,EAAE,UAAU,EAAuB,MAAM,KAAK,CAAC;AAErF,MAAM,MAAM,mBAAmB,GAAG,SAAS,MAAM,EAAE,GAAG,WAAW,MAAM,EAAE,CAAC;AAE1E,MAAM,WAAW,0BAA0B;IACvC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,CAAC;CACzD;AAED,iBAAS,+BAA+B,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAKxH;AAED,QAAA,MAAM,aAAa;;CAElB,CAAC;AAEF,QAAA,MAAM,UAAU;;CAEf,CAAC;AAEF,KAAK,cAAc,GAAG,OAAO,UAAU,GAAG,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAQpE,KAAK,aAAa,GAAG,OAAO,CAAC,GAAG;IAC5B,MAAM,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,QAAA,MAAM,MAAM,EAKN,aAAa,CAAC;AAEpB,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;AACvB,OAAO,EAAE,aAAa,IAAI,MAAM,EAAE,CAAC;AAEnC,MAAM,WAAW,kBAAkB;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE;QACL,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;KAC7D,CAAC;CACL;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,CAyEzF;AAED,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,SAAS,IAAI,aAAa,EAAE,UAAU,EAAuB,MAAM,KAAK,CAAC;AAErF,MAAM,MAAM,mBAAmB,GAAG,SAAS,MAAM,EAAE,GAAG,WAAW,MAAM,EAAE,CAAC;AAE1E,MAAM,WAAW,0BAA0B;IACvC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,CAAC;CACzD;AAED,iBAAS,+BAA+B,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAKxH;AAED,QAAA,MAAM,aAAa;;CAElB,CAAC;AAEF,QAAA,MAAM,UAAU;;CAEf,CAAC;AAEF,KAAK,cAAc,GAAG,OAAO,UAAU,GAAG,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAQpE,KAAK,aAAa,GAAG,OAAO,CAAC,GAAG;IAC5B,MAAM,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,QAAA,MAAM,MAAM,EAKN,aAAa,CAAC;AAEpB,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;AACvB,OAAO,EAAE,aAAa,IAAI,MAAM,EAAE,CAAC;AAEnC,MAAM,WAAW,kBAAkB;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE;QACL,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;KAC7D,CAAC;CACL;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,CA2EzF;AAED,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export type Provider = "sentry" | "glitchtip" | "discord" | "none";
2
+ export type TelemetryProvider = Provider;
2
3
  export interface TelemetryConfig {
3
4
  provider: Provider;
4
5
  dsn?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/telemetry/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/telemetry/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"sprint.d.ts","sourceRoot":"","sources":["../../src/sprint.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAA+B,gBAAgB,EAAoB,MAAM,SAAS,CAAC;AACnG,OAAO,OAAO,EAAE,EAAE,WAAW,EAAoD,MAAM,SAAS,CAAC;AAejG,eAAO,MAAM,aAAa,SAAQ,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AAwCnC,qBAAa,MAAM;IACR,GAAG,EAAE,WAAW,CAAC;IACxB,OAAO,CAAC,IAAI,CAAwD;IACpE,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,OAAO,CAUb;IACF,OAAO,CAAC,gBAAgB,CAIhB;;YA2EM,IAAI;IA8BlB,OAAO,CAAC,YAAY;IAiDpB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;YACW,eAAe;IAgC7B,OAAO,CAAC,eAAe;YAcT,UAAU;YAkFV,YAAY;IAmB1B,OAAO,CAAC,YAAY;IAgCpB,+BAA+B;IAC/B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,mBAAmB;IA8I3B,OAAO,CAAC,kBAAkB;IAgD1B,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,mBAAmB;IAoCpB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,EAAE,YAAY,CAAC,EAAE,OAAO;IAYlF,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI;CA0DzC"}
1
+ {"version":3,"file":"sprint.d.ts","sourceRoot":"","sources":["../../src/sprint.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAA+B,gBAAgB,EAAoB,MAAM,SAAS,CAAC;AACnG,OAAO,OAAO,EAAE,EAAE,WAAW,EAAoD,MAAM,SAAS,CAAC;AAejG,eAAO,MAAM,aAAa,SAAQ,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AAwCnC,qBAAa,MAAM;IACR,GAAG,EAAE,WAAW,CAAC;IACxB,OAAO,CAAC,IAAI,CAAwD;IACpE,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,OAAO,CAUb;IACF,OAAO,CAAC,gBAAgB,CAIhB;;YA2EM,IAAI;IA8BlB,OAAO,CAAC,YAAY;IAiDpB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;YACW,eAAe;IAgC7B,OAAO,CAAC,eAAe;YAcT,UAAU;YAiFV,YAAY;IAmB1B,OAAO,CAAC,YAAY;IAgCpB,+BAA+B;IAC/B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,mBAAmB;IA+K3B,OAAO,CAAC,kBAAkB;IAqC1B,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,mBAAmB;IA+BpB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAClC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACpC,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,gBAAgB,EAAE,YAAY,CAAC,EAAE,OAAO;IAYlF,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI;CA0DzC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprint-es",
3
- "version": "0.0.78",
3
+ "version": "0.0.80",
4
4
  "description": "Sprint - Quickly API",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",