sprint-es 0.0.73 → 0.0.75
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/index.cjs +204 -4
- package/dist/cjs/modules/schemas/index.cjs +50 -0
- package/dist/esm/index.js +204 -4
- package/dist/esm/modules/schemas/index.js +52 -1
- package/dist/types/middleware.d.ts.map +1 -1
- package/dist/types/modules/schemas/index.d.ts +12 -0
- package/dist/types/modules/schemas/index.d.ts.map +1 -1
- package/dist/types/modules/schemas/types.d.ts +4 -0
- package/dist/types/modules/schemas/types.d.ts.map +1 -1
- package/dist/types/sprint.d.ts +1 -0
- package/dist/types/sprint.d.ts.map +1 -1
- package/dist/types/types.d.ts +16 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +112 -112
package/dist/cjs/index.cjs
CHANGED
|
@@ -157,7 +157,6 @@ class Sprint {
|
|
|
157
157
|
enabled: finalConfig.openapi?.swaggerUi?.enabled ?? false
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
|
-
if (this.openapi.generateOnBuild === true) console.log(`[Sprint] ⚠️ openapi.generateOnBuild is enabled but this option makes nothing for now`);
|
|
161
160
|
this.loadDefaults();
|
|
162
161
|
this.loadHealthcheck();
|
|
163
162
|
this.routesLoaded = this.init();
|
|
@@ -170,6 +169,13 @@ class Sprint {
|
|
|
170
169
|
try {
|
|
171
170
|
const swaggerUi = await import("swagger-ui-express");
|
|
172
171
|
const ui = swaggerUi.default;
|
|
172
|
+
this.app.use("/swagger", (req, res, next) => {
|
|
173
|
+
res.setHeader(
|
|
174
|
+
"Content-Security-Policy",
|
|
175
|
+
"default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https:"
|
|
176
|
+
);
|
|
177
|
+
next();
|
|
178
|
+
});
|
|
173
179
|
this.app.use("/swagger", ui.serve, ui.setup(void 0, {
|
|
174
180
|
swaggerUrl: "/openapi.json"
|
|
175
181
|
}));
|
|
@@ -433,6 +439,7 @@ class Sprint {
|
|
|
433
439
|
}
|
|
434
440
|
}
|
|
435
441
|
};
|
|
442
|
+
let allParams = [];
|
|
436
443
|
if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
|
|
437
444
|
try {
|
|
438
445
|
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
@@ -452,11 +459,81 @@ class Sprint {
|
|
|
452
459
|
if (route.schema?.queryParams) {
|
|
453
460
|
try {
|
|
454
461
|
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
455
|
-
if (params.length > 0)
|
|
462
|
+
if (params.length > 0) allParams.push(...params);
|
|
456
463
|
} catch (e) {
|
|
457
464
|
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
458
465
|
}
|
|
459
466
|
}
|
|
467
|
+
if (route.schema?.headers) {
|
|
468
|
+
try {
|
|
469
|
+
const headers = this.zodHeadersToOpenAPI(route.schema.headers);
|
|
470
|
+
if (headers.length > 0) allParams.push(...headers);
|
|
471
|
+
} catch (e) {
|
|
472
|
+
console.warn("[Sprint] Failed to convert headers schema:", e);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (this.openapi.generateOnBuild) {
|
|
476
|
+
try {
|
|
477
|
+
const routeMiddlewares = this.getMiddlewaresForRoute(route.path);
|
|
478
|
+
for (const mw of this.loadedMiddlewares) {
|
|
479
|
+
const includePatterns = Array.isArray(mw.include) ? mw.include : [mw.include || "/**"];
|
|
480
|
+
const excludePatterns = Array.isArray(mw.exclude) ? mw.exclude : mw.exclude ? [mw.exclude] : [];
|
|
481
|
+
const isIncluded = matchesPatterns(includePatterns, route.path);
|
|
482
|
+
const isExcluded = excludePatterns.length > 0 && matchesPatterns(excludePatterns, route.path);
|
|
483
|
+
if (isIncluded && !isExcluded && mw.__sprintMiddlewareSchema) {
|
|
484
|
+
const mwSchema = mw.__sprintMiddlewareSchema;
|
|
485
|
+
if (mwSchema.queryParams) {
|
|
486
|
+
const params = this.zodParamsToOpenAPI(mwSchema.queryParams);
|
|
487
|
+
if (params.length > 0) allParams.push(...params);
|
|
488
|
+
}
|
|
489
|
+
if (mwSchema.headers) {
|
|
490
|
+
const headers = this.zodHeadersToOpenAPI(mwSchema.headers);
|
|
491
|
+
if (headers.length > 0) allParams.push(...headers);
|
|
492
|
+
}
|
|
493
|
+
if (mwSchema.sprint?.authorization) {
|
|
494
|
+
const authSchema = mwSchema.sprint.authorization;
|
|
495
|
+
const description = authSchema._def?.description;
|
|
496
|
+
let sources = ["query:token", "headers:authorization"];
|
|
497
|
+
if (description) {
|
|
498
|
+
try {
|
|
499
|
+
const parsed = JSON.parse(description);
|
|
500
|
+
if (parsed.__sprintAuthorization && parsed.sources) {
|
|
501
|
+
sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
502
|
+
}
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
for (const source of sources) {
|
|
507
|
+
const [type, key] = source.split(":");
|
|
508
|
+
if (type === "query") {
|
|
509
|
+
allParams.push({
|
|
510
|
+
name: key,
|
|
511
|
+
in: "query",
|
|
512
|
+
required: true,
|
|
513
|
+
schema: { type: "string" }
|
|
514
|
+
});
|
|
515
|
+
} else if (type === "headers") {
|
|
516
|
+
allParams.push({
|
|
517
|
+
name: key,
|
|
518
|
+
in: "header",
|
|
519
|
+
required: true,
|
|
520
|
+
schema: { type: "string" }
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
} catch (e) {
|
|
528
|
+
console.warn("[Sprint] Failed to add middleware schemas to OpenAPI:", e);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
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
|
+
);
|
|
535
|
+
routeSpec.parameters = uniqueParams;
|
|
536
|
+
}
|
|
460
537
|
paths[route.path][method] = routeSpec;
|
|
461
538
|
}
|
|
462
539
|
return {
|
|
@@ -530,6 +607,33 @@ class Sprint {
|
|
|
530
607
|
}
|
|
531
608
|
return params;
|
|
532
609
|
}
|
|
610
|
+
zodHeadersToOpenAPI(schema) {
|
|
611
|
+
if (!schema) return [];
|
|
612
|
+
const headers = [];
|
|
613
|
+
const shape = schema.shape || schema._def?.shape();
|
|
614
|
+
if (!shape) return [];
|
|
615
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
616
|
+
const zodDef = value._def;
|
|
617
|
+
const typeName = zodDef?.typeName;
|
|
618
|
+
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
|
+
}
|
|
628
|
+
headers.push({
|
|
629
|
+
name: key,
|
|
630
|
+
in: "header",
|
|
631
|
+
required: !zodDef?.isOptional,
|
|
632
|
+
schema: paramSchema
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
return headers;
|
|
636
|
+
}
|
|
533
637
|
// HTTP Methods (prefix is applied automatically).
|
|
534
638
|
get(path2, handler) {
|
|
535
639
|
return this.app.get(this.applyPrefix(path2), handler);
|
|
@@ -606,6 +710,88 @@ class Sprint {
|
|
|
606
710
|
});
|
|
607
711
|
}
|
|
608
712
|
}
|
|
713
|
+
function createSchemaValidationMiddleware(schema) {
|
|
714
|
+
return (req, res, next) => {
|
|
715
|
+
const errors = [];
|
|
716
|
+
if (schema.body) {
|
|
717
|
+
const result = schema.body.safeParse(req.body);
|
|
718
|
+
if (!result.success) {
|
|
719
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
720
|
+
location: "body",
|
|
721
|
+
path: issue.path.join("."),
|
|
722
|
+
message: issue.message
|
|
723
|
+
})));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (schema.queryParams) {
|
|
727
|
+
const result = schema.queryParams.safeParse(req.query);
|
|
728
|
+
if (!result.success) {
|
|
729
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
730
|
+
location: "queryParams",
|
|
731
|
+
path: issue.path.join("."),
|
|
732
|
+
message: issue.message
|
|
733
|
+
})));
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (schema.params) {
|
|
737
|
+
const result = schema.params.safeParse(req.params);
|
|
738
|
+
if (!result.success) {
|
|
739
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
740
|
+
location: "params",
|
|
741
|
+
path: issue.path.join("."),
|
|
742
|
+
message: issue.message
|
|
743
|
+
})));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (schema.headers) {
|
|
747
|
+
const result = schema.headers.safeParse(req.headers);
|
|
748
|
+
if (!result.success) {
|
|
749
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
750
|
+
location: "headers",
|
|
751
|
+
path: issue.path.join("."),
|
|
752
|
+
message: issue.message
|
|
753
|
+
})));
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (schema.sprint?.authorization) {
|
|
757
|
+
const authSchema = schema.sprint.authorization;
|
|
758
|
+
const description = authSchema._def?.description;
|
|
759
|
+
let sources = ["query:token", "headers:authorization"];
|
|
760
|
+
if (description) {
|
|
761
|
+
try {
|
|
762
|
+
const parsed = JSON.parse(description);
|
|
763
|
+
if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
764
|
+
} catch {
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
let authValue;
|
|
768
|
+
for (const source of sources) {
|
|
769
|
+
const [type, key] = source.split(":");
|
|
770
|
+
if (type === "query") {
|
|
771
|
+
const value = req.query[key];
|
|
772
|
+
if (typeof value === "string" && value.length > 0) {
|
|
773
|
+
authValue = value;
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
} else if (type === "headers") {
|
|
777
|
+
const value = req.headers[key.toLowerCase()];
|
|
778
|
+
if (typeof value === "string" && value.length > 0) {
|
|
779
|
+
authValue = value;
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "string" && value[0].length > 0) {
|
|
783
|
+
authValue = value[0];
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (!authValue) errors.push({ location: "sprint.authorization", path: "authorization", message: "Authorization header or query parameter not found" });
|
|
789
|
+
else req.sprint.authorization = authValue;
|
|
790
|
+
}
|
|
791
|
+
if (errors.length > 0) return res.status(400).json({ error: "Validation failed", details: errors });
|
|
792
|
+
next();
|
|
793
|
+
};
|
|
794
|
+
}
|
|
609
795
|
function defineMiddleware(config) {
|
|
610
796
|
const wrapHandler = (handler) => {
|
|
611
797
|
return (req, res, next) => {
|
|
@@ -613,10 +799,24 @@ function defineMiddleware(config) {
|
|
|
613
799
|
if (result instanceof Promise) result.catch(next);
|
|
614
800
|
};
|
|
615
801
|
};
|
|
616
|
-
|
|
802
|
+
const handlers = [];
|
|
803
|
+
if (config.schema) {
|
|
804
|
+
handlers.push(createSchemaValidationMiddleware(config.schema));
|
|
805
|
+
}
|
|
806
|
+
const originalHandler = config.handler;
|
|
807
|
+
if (Array.isArray(originalHandler)) {
|
|
808
|
+
handlers.push(...originalHandler.map(wrapHandler));
|
|
809
|
+
} else {
|
|
810
|
+
handlers.push(wrapHandler(originalHandler));
|
|
811
|
+
}
|
|
812
|
+
const finalConfig = {
|
|
617
813
|
...config,
|
|
618
|
-
handler:
|
|
814
|
+
handler: handlers
|
|
619
815
|
};
|
|
816
|
+
if (config.schema) {
|
|
817
|
+
finalConfig.__sprintMiddlewareSchema = config.schema;
|
|
818
|
+
}
|
|
819
|
+
return finalConfig;
|
|
620
820
|
}
|
|
621
821
|
const Router = () => express.Router();
|
|
622
822
|
exports.Router = Router;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const zod = require("zod");
|
|
4
|
+
function createSprintAuthorizationSchema(options) {
|
|
5
|
+
const defaultSources = ["query:token", "headers:authorization"];
|
|
6
|
+
const sources = options?.sources ? Array.isArray(options.sources) ? options.sources : [options.sources] : defaultSources;
|
|
7
|
+
return zod.z.string().describe(JSON.stringify({ __sprintAuthorization: true, sources }));
|
|
8
|
+
}
|
|
9
|
+
const sprint = {
|
|
10
|
+
authorization: createSprintAuthorizationSchema
|
|
11
|
+
};
|
|
4
12
|
function parseSchema(schema, data) {
|
|
5
13
|
const result = schema.safeParse(data);
|
|
6
14
|
if (!result.success) {
|
|
@@ -29,6 +37,47 @@ function defineRouteSchema(schema) {
|
|
|
29
37
|
const result = parseSchema(schema.params, req.params);
|
|
30
38
|
if (!result.success) errors.push(...result.errors.map((e) => ({ location: "params", ...e })));
|
|
31
39
|
}
|
|
40
|
+
if (schema.headers) {
|
|
41
|
+
const result = parseSchema(schema.headers, req.headers);
|
|
42
|
+
if (!result.success) errors.push(...result.errors.map((e) => ({ location: "headers", ...e })));
|
|
43
|
+
}
|
|
44
|
+
if (schema.sprint?.authorization) {
|
|
45
|
+
const authSchema = schema.sprint.authorization;
|
|
46
|
+
const description = authSchema._def?.description;
|
|
47
|
+
let sources = ["query:token", "headers:authorization"];
|
|
48
|
+
if (description) {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(description);
|
|
51
|
+
if (parsed.__sprintAuthorization && parsed.sources) {
|
|
52
|
+
sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let authValue;
|
|
58
|
+
for (const source of sources) {
|
|
59
|
+
const [type, key] = source.split(":");
|
|
60
|
+
if (type === "query") {
|
|
61
|
+
const value = req.query[key];
|
|
62
|
+
if (typeof value === "string" && value.length > 0) {
|
|
63
|
+
authValue = value;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
} else if (type === "headers") {
|
|
67
|
+
const value = req.headers[key.toLowerCase()];
|
|
68
|
+
if (typeof value === "string" && value.length > 0) {
|
|
69
|
+
authValue = value;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "string" && value[0].length > 0) {
|
|
73
|
+
authValue = value[0];
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!authValue) errors.push({ location: "sprint.authorization", path: "authorization", message: "Authorization header or query parameter not found" });
|
|
79
|
+
else req.sprint.authorization = authValue;
|
|
80
|
+
}
|
|
32
81
|
if (errors.length > 0) return res.status(400).json({ error: "Validation failed", details: errors });
|
|
33
82
|
next();
|
|
34
83
|
};
|
|
@@ -40,3 +89,4 @@ Object.defineProperty(exports, "z", {
|
|
|
40
89
|
get: () => zod.z
|
|
41
90
|
});
|
|
42
91
|
exports.defineRouteSchema = defineRouteSchema;
|
|
92
|
+
exports.sprint = sprint;
|
package/dist/esm/index.js
CHANGED
|
@@ -132,7 +132,6 @@ class Sprint {
|
|
|
132
132
|
enabled: finalConfig.openapi?.swaggerUi?.enabled ?? false
|
|
133
133
|
}
|
|
134
134
|
};
|
|
135
|
-
if (this.openapi.generateOnBuild === true) console.log(`[Sprint] ⚠️ openapi.generateOnBuild is enabled but this option makes nothing for now`);
|
|
136
135
|
this.loadDefaults();
|
|
137
136
|
this.loadHealthcheck();
|
|
138
137
|
this.routesLoaded = this.init();
|
|
@@ -145,6 +144,13 @@ class Sprint {
|
|
|
145
144
|
try {
|
|
146
145
|
const swaggerUi = await import("swagger-ui-express");
|
|
147
146
|
const ui = swaggerUi.default;
|
|
147
|
+
this.app.use("/swagger", (req, res, next) => {
|
|
148
|
+
res.setHeader(
|
|
149
|
+
"Content-Security-Policy",
|
|
150
|
+
"default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https:"
|
|
151
|
+
);
|
|
152
|
+
next();
|
|
153
|
+
});
|
|
148
154
|
this.app.use("/swagger", ui.serve, ui.setup(void 0, {
|
|
149
155
|
swaggerUrl: "/openapi.json"
|
|
150
156
|
}));
|
|
@@ -408,6 +414,7 @@ class Sprint {
|
|
|
408
414
|
}
|
|
409
415
|
}
|
|
410
416
|
};
|
|
417
|
+
let allParams = [];
|
|
411
418
|
if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
|
|
412
419
|
try {
|
|
413
420
|
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
@@ -427,11 +434,81 @@ class Sprint {
|
|
|
427
434
|
if (route.schema?.queryParams) {
|
|
428
435
|
try {
|
|
429
436
|
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
430
|
-
if (params.length > 0)
|
|
437
|
+
if (params.length > 0) allParams.push(...params);
|
|
431
438
|
} catch (e) {
|
|
432
439
|
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
433
440
|
}
|
|
434
441
|
}
|
|
442
|
+
if (route.schema?.headers) {
|
|
443
|
+
try {
|
|
444
|
+
const headers = this.zodHeadersToOpenAPI(route.schema.headers);
|
|
445
|
+
if (headers.length > 0) allParams.push(...headers);
|
|
446
|
+
} catch (e) {
|
|
447
|
+
console.warn("[Sprint] Failed to convert headers schema:", e);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (this.openapi.generateOnBuild) {
|
|
451
|
+
try {
|
|
452
|
+
const routeMiddlewares = this.getMiddlewaresForRoute(route.path);
|
|
453
|
+
for (const mw of this.loadedMiddlewares) {
|
|
454
|
+
const includePatterns = Array.isArray(mw.include) ? mw.include : [mw.include || "/**"];
|
|
455
|
+
const excludePatterns = Array.isArray(mw.exclude) ? mw.exclude : mw.exclude ? [mw.exclude] : [];
|
|
456
|
+
const isIncluded = matchesPatterns(includePatterns, route.path);
|
|
457
|
+
const isExcluded = excludePatterns.length > 0 && matchesPatterns(excludePatterns, route.path);
|
|
458
|
+
if (isIncluded && !isExcluded && mw.__sprintMiddlewareSchema) {
|
|
459
|
+
const mwSchema = mw.__sprintMiddlewareSchema;
|
|
460
|
+
if (mwSchema.queryParams) {
|
|
461
|
+
const params = this.zodParamsToOpenAPI(mwSchema.queryParams);
|
|
462
|
+
if (params.length > 0) allParams.push(...params);
|
|
463
|
+
}
|
|
464
|
+
if (mwSchema.headers) {
|
|
465
|
+
const headers = this.zodHeadersToOpenAPI(mwSchema.headers);
|
|
466
|
+
if (headers.length > 0) allParams.push(...headers);
|
|
467
|
+
}
|
|
468
|
+
if (mwSchema.sprint?.authorization) {
|
|
469
|
+
const authSchema = mwSchema.sprint.authorization;
|
|
470
|
+
const description = authSchema._def?.description;
|
|
471
|
+
let sources = ["query:token", "headers:authorization"];
|
|
472
|
+
if (description) {
|
|
473
|
+
try {
|
|
474
|
+
const parsed = JSON.parse(description);
|
|
475
|
+
if (parsed.__sprintAuthorization && parsed.sources) {
|
|
476
|
+
sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
477
|
+
}
|
|
478
|
+
} catch {
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
for (const source of sources) {
|
|
482
|
+
const [type, key] = source.split(":");
|
|
483
|
+
if (type === "query") {
|
|
484
|
+
allParams.push({
|
|
485
|
+
name: key,
|
|
486
|
+
in: "query",
|
|
487
|
+
required: true,
|
|
488
|
+
schema: { type: "string" }
|
|
489
|
+
});
|
|
490
|
+
} else if (type === "headers") {
|
|
491
|
+
allParams.push({
|
|
492
|
+
name: key,
|
|
493
|
+
in: "header",
|
|
494
|
+
required: true,
|
|
495
|
+
schema: { type: "string" }
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
} catch (e) {
|
|
503
|
+
console.warn("[Sprint] Failed to add middleware schemas to OpenAPI:", e);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
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
|
+
);
|
|
510
|
+
routeSpec.parameters = uniqueParams;
|
|
511
|
+
}
|
|
435
512
|
paths[route.path][method] = routeSpec;
|
|
436
513
|
}
|
|
437
514
|
return {
|
|
@@ -505,6 +582,33 @@ class Sprint {
|
|
|
505
582
|
}
|
|
506
583
|
return params;
|
|
507
584
|
}
|
|
585
|
+
zodHeadersToOpenAPI(schema) {
|
|
586
|
+
if (!schema) return [];
|
|
587
|
+
const headers = [];
|
|
588
|
+
const shape = schema.shape || schema._def?.shape();
|
|
589
|
+
if (!shape) return [];
|
|
590
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
591
|
+
const zodDef = value._def;
|
|
592
|
+
const typeName = zodDef?.typeName;
|
|
593
|
+
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
|
+
}
|
|
603
|
+
headers.push({
|
|
604
|
+
name: key,
|
|
605
|
+
in: "header",
|
|
606
|
+
required: !zodDef?.isOptional,
|
|
607
|
+
schema: paramSchema
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
return headers;
|
|
611
|
+
}
|
|
508
612
|
// HTTP Methods (prefix is applied automatically).
|
|
509
613
|
get(path2, handler) {
|
|
510
614
|
return this.app.get(this.applyPrefix(path2), handler);
|
|
@@ -581,6 +685,88 @@ class Sprint {
|
|
|
581
685
|
});
|
|
582
686
|
}
|
|
583
687
|
}
|
|
688
|
+
function createSchemaValidationMiddleware(schema) {
|
|
689
|
+
return (req, res, next) => {
|
|
690
|
+
const errors = [];
|
|
691
|
+
if (schema.body) {
|
|
692
|
+
const result = schema.body.safeParse(req.body);
|
|
693
|
+
if (!result.success) {
|
|
694
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
695
|
+
location: "body",
|
|
696
|
+
path: issue.path.join("."),
|
|
697
|
+
message: issue.message
|
|
698
|
+
})));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if (schema.queryParams) {
|
|
702
|
+
const result = schema.queryParams.safeParse(req.query);
|
|
703
|
+
if (!result.success) {
|
|
704
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
705
|
+
location: "queryParams",
|
|
706
|
+
path: issue.path.join("."),
|
|
707
|
+
message: issue.message
|
|
708
|
+
})));
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (schema.params) {
|
|
712
|
+
const result = schema.params.safeParse(req.params);
|
|
713
|
+
if (!result.success) {
|
|
714
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
715
|
+
location: "params",
|
|
716
|
+
path: issue.path.join("."),
|
|
717
|
+
message: issue.message
|
|
718
|
+
})));
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (schema.headers) {
|
|
722
|
+
const result = schema.headers.safeParse(req.headers);
|
|
723
|
+
if (!result.success) {
|
|
724
|
+
errors.push(...result.error.issues.map((issue) => ({
|
|
725
|
+
location: "headers",
|
|
726
|
+
path: issue.path.join("."),
|
|
727
|
+
message: issue.message
|
|
728
|
+
})));
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (schema.sprint?.authorization) {
|
|
732
|
+
const authSchema = schema.sprint.authorization;
|
|
733
|
+
const description = authSchema._def?.description;
|
|
734
|
+
let sources = ["query:token", "headers:authorization"];
|
|
735
|
+
if (description) {
|
|
736
|
+
try {
|
|
737
|
+
const parsed = JSON.parse(description);
|
|
738
|
+
if (parsed.__sprintAuthorization && parsed.sources) sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
739
|
+
} catch {
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
let authValue;
|
|
743
|
+
for (const source of sources) {
|
|
744
|
+
const [type, key] = source.split(":");
|
|
745
|
+
if (type === "query") {
|
|
746
|
+
const value = req.query[key];
|
|
747
|
+
if (typeof value === "string" && value.length > 0) {
|
|
748
|
+
authValue = value;
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
} else if (type === "headers") {
|
|
752
|
+
const value = req.headers[key.toLowerCase()];
|
|
753
|
+
if (typeof value === "string" && value.length > 0) {
|
|
754
|
+
authValue = value;
|
|
755
|
+
break;
|
|
756
|
+
}
|
|
757
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "string" && value[0].length > 0) {
|
|
758
|
+
authValue = value[0];
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
if (!authValue) errors.push({ location: "sprint.authorization", path: "authorization", message: "Authorization header or query parameter not found" });
|
|
764
|
+
else req.sprint.authorization = authValue;
|
|
765
|
+
}
|
|
766
|
+
if (errors.length > 0) return res.status(400).json({ error: "Validation failed", details: errors });
|
|
767
|
+
next();
|
|
768
|
+
};
|
|
769
|
+
}
|
|
584
770
|
function defineMiddleware(config) {
|
|
585
771
|
const wrapHandler = (handler) => {
|
|
586
772
|
return (req, res, next) => {
|
|
@@ -588,10 +774,24 @@ function defineMiddleware(config) {
|
|
|
588
774
|
if (result instanceof Promise) result.catch(next);
|
|
589
775
|
};
|
|
590
776
|
};
|
|
591
|
-
|
|
777
|
+
const handlers = [];
|
|
778
|
+
if (config.schema) {
|
|
779
|
+
handlers.push(createSchemaValidationMiddleware(config.schema));
|
|
780
|
+
}
|
|
781
|
+
const originalHandler = config.handler;
|
|
782
|
+
if (Array.isArray(originalHandler)) {
|
|
783
|
+
handlers.push(...originalHandler.map(wrapHandler));
|
|
784
|
+
} else {
|
|
785
|
+
handlers.push(wrapHandler(originalHandler));
|
|
786
|
+
}
|
|
787
|
+
const finalConfig = {
|
|
592
788
|
...config,
|
|
593
|
-
handler:
|
|
789
|
+
handler: handlers
|
|
594
790
|
};
|
|
791
|
+
if (config.schema) {
|
|
792
|
+
finalConfig.__sprintMiddlewareSchema = config.schema;
|
|
793
|
+
}
|
|
794
|
+
return finalConfig;
|
|
595
795
|
}
|
|
596
796
|
const Router = () => Router$1();
|
|
597
797
|
export {
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
|
+
function createSprintAuthorizationSchema(options) {
|
|
4
|
+
const defaultSources = ["query:token", "headers:authorization"];
|
|
5
|
+
const sources = options?.sources ? Array.isArray(options.sources) ? options.sources : [options.sources] : defaultSources;
|
|
6
|
+
return z.string().describe(JSON.stringify({ __sprintAuthorization: true, sources }));
|
|
7
|
+
}
|
|
8
|
+
const sprint = {
|
|
9
|
+
authorization: createSprintAuthorizationSchema
|
|
10
|
+
};
|
|
2
11
|
function parseSchema(schema, data) {
|
|
3
12
|
const result = schema.safeParse(data);
|
|
4
13
|
if (!result.success) {
|
|
@@ -27,6 +36,47 @@ function defineRouteSchema(schema) {
|
|
|
27
36
|
const result = parseSchema(schema.params, req.params);
|
|
28
37
|
if (!result.success) errors.push(...result.errors.map((e) => ({ location: "params", ...e })));
|
|
29
38
|
}
|
|
39
|
+
if (schema.headers) {
|
|
40
|
+
const result = parseSchema(schema.headers, req.headers);
|
|
41
|
+
if (!result.success) errors.push(...result.errors.map((e) => ({ location: "headers", ...e })));
|
|
42
|
+
}
|
|
43
|
+
if (schema.sprint?.authorization) {
|
|
44
|
+
const authSchema = schema.sprint.authorization;
|
|
45
|
+
const description = authSchema._def?.description;
|
|
46
|
+
let sources = ["query:token", "headers:authorization"];
|
|
47
|
+
if (description) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(description);
|
|
50
|
+
if (parsed.__sprintAuthorization && parsed.sources) {
|
|
51
|
+
sources = Array.isArray(parsed.sources) ? parsed.sources : [parsed.sources];
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let authValue;
|
|
57
|
+
for (const source of sources) {
|
|
58
|
+
const [type, key] = source.split(":");
|
|
59
|
+
if (type === "query") {
|
|
60
|
+
const value = req.query[key];
|
|
61
|
+
if (typeof value === "string" && value.length > 0) {
|
|
62
|
+
authValue = value;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
} else if (type === "headers") {
|
|
66
|
+
const value = req.headers[key.toLowerCase()];
|
|
67
|
+
if (typeof value === "string" && value.length > 0) {
|
|
68
|
+
authValue = value;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "string" && value[0].length > 0) {
|
|
72
|
+
authValue = value[0];
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!authValue) errors.push({ location: "sprint.authorization", path: "authorization", message: "Authorization header or query parameter not found" });
|
|
78
|
+
else req.sprint.authorization = authValue;
|
|
79
|
+
}
|
|
30
80
|
if (errors.length > 0) return res.status(400).json({ error: "Validation failed", details: errors });
|
|
31
81
|
next();
|
|
32
82
|
};
|
|
@@ -35,5 +85,6 @@ function defineRouteSchema(schema) {
|
|
|
35
85
|
}
|
|
36
86
|
export {
|
|
37
87
|
defineRouteSchema,
|
|
38
|
-
|
|
88
|
+
sprint,
|
|
89
|
+
z2 as z
|
|
39
90
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,
|
|
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,10 +1,22 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
2
|
import { z, ZodSchema as ZodSchemaType, ZodTypeDef } from 'zod';
|
|
3
3
|
export { z };
|
|
4
|
+
export type AuthorizationSource = `query:${string}` | `headers:${string}`;
|
|
5
|
+
export interface SprintAuthorizationOptions {
|
|
6
|
+
sources?: AuthorizationSource | AuthorizationSource[];
|
|
7
|
+
}
|
|
8
|
+
declare function createSprintAuthorizationSchema(options?: SprintAuthorizationOptions): ZodSchemaType<string, ZodTypeDef, string>;
|
|
9
|
+
export declare const sprint: {
|
|
10
|
+
authorization: typeof createSprintAuthorizationSchema;
|
|
11
|
+
};
|
|
4
12
|
export interface RouteSchemaOptions {
|
|
5
13
|
body?: ZodSchemaType<any, ZodTypeDef, any>;
|
|
6
14
|
queryParams?: ZodSchemaType<any, ZodTypeDef, any>;
|
|
7
15
|
params?: ZodSchemaType<any, ZodTypeDef, any>;
|
|
16
|
+
headers?: ZodSchemaType<any, ZodTypeDef, any>;
|
|
17
|
+
sprint?: {
|
|
18
|
+
authorization?: ZodSchemaType<string, ZodTypeDef, string>;
|
|
19
|
+
};
|
|
8
20
|
}
|
|
9
21
|
export declare function defineRouteSchema<T extends RouteSchemaOptions>(schema: T): RequestHandler;
|
|
10
22
|
export type { ZodSchema, ZodMiddlewareOptions } from './types';
|
|
@@ -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,EAAY,MAAM,KAAK,CAAC;AAE1E,OAAO,EAAE,CAAC,EAAE,CAAC;AAEb,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;
|
|
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,EAAY,MAAM,KAAK,CAAC;AAE1E,OAAO,EAAE,CAAC,EAAE,CAAC;AAEb,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,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAEvC,MAAM,WAAW,oBAAoB;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/schemas/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAEvC,MAAM,WAAW,oBAAoB;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE;QACL,aAAa,CAAC,EAAE,SAAS,CAAC;KAC7B,CAAC;CACL"}
|
package/dist/types/sprint.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ export declare class Sprint {
|
|
|
36
36
|
private generateOpenAPISpec;
|
|
37
37
|
private zodSchemaToOpenAPI;
|
|
38
38
|
private zodParamsToOpenAPI;
|
|
39
|
+
private zodHeadersToOpenAPI;
|
|
39
40
|
get(path: string, handler: Handler): express.Application;
|
|
40
41
|
post(path: string, handler: Handler): express.Application;
|
|
41
42
|
put(path: string, handler: Handler): express.Application;
|
|
@@ -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;;
|
|
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"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
2
|
+
import { ZodSchema } from './modules/schemas/types';
|
|
2
3
|
export type AsyncRequestHandler = (req: Request, res: Response, next: NextFunction) => Promise<any>;
|
|
3
4
|
export type Handler = (req: Request, res: Response, next: NextFunction) => any;
|
|
4
5
|
export type AuthorizationSource = `query:${string}` | `headers:${string}`;
|
|
5
6
|
export interface SprintRequest {
|
|
6
7
|
getAuthorization: (sources?: AuthorizationSource | AuthorizationSource[]) => string | undefined;
|
|
8
|
+
authorization?: string;
|
|
7
9
|
}
|
|
8
10
|
export type SprintResponse = Response;
|
|
9
11
|
declare global {
|
|
@@ -14,6 +16,15 @@ declare global {
|
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
}
|
|
19
|
+
export interface MiddlewareSchema {
|
|
20
|
+
body?: ZodSchema;
|
|
21
|
+
queryParams?: ZodSchema;
|
|
22
|
+
params?: ZodSchema;
|
|
23
|
+
headers?: ZodSchema;
|
|
24
|
+
sprint?: {
|
|
25
|
+
authorization?: ZodSchema;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
17
28
|
/**
|
|
18
29
|
* Configuration for a middleware defined in the middlewares folder.
|
|
19
30
|
* Export this from your middleware file using `defineMiddleware()`.
|
|
@@ -43,6 +54,11 @@ export interface MiddlewareConfig {
|
|
|
43
54
|
priority?: number;
|
|
44
55
|
/** Optional name for logging purposes */
|
|
45
56
|
name?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Schema for request validation and OpenAPI generation.
|
|
59
|
+
* Supports body, queryParams, params, headers, and sprint.authorization.
|
|
60
|
+
*/
|
|
61
|
+
schema?: MiddlewareSchema;
|
|
46
62
|
}
|
|
47
63
|
export interface LoadedMiddleware extends MiddlewareConfig {
|
|
48
64
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,122 +1,122 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
"name": "sprint-es",
|
|
3
|
+
"version": "0.0.75",
|
|
4
|
+
"description": "Sprint - Quickly API",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/types/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": "dist/esm/cli.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/types/index.d.ts",
|
|
13
|
+
"require": "./dist/cjs/index.cjs",
|
|
14
|
+
"import": "./dist/esm/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./logger": {
|
|
17
|
+
"types": "./dist/types/modules/logger/index.d.ts",
|
|
18
|
+
"require": "./dist/cjs/modules/logger/index.cjs",
|
|
19
|
+
"import": "./dist/esm/modules/logger/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./rate-limit": {
|
|
22
|
+
"types": "./dist/types/modules/rate-limit/index.d.ts",
|
|
23
|
+
"require": "./dist/cjs/modules/rate-limit/index.cjs",
|
|
24
|
+
"import": "./dist/esm/modules/rate-limit/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./telemetry": {
|
|
27
|
+
"types": "./dist/types/modules/telemetry/index.d.ts",
|
|
28
|
+
"require": "./dist/cjs/modules/telemetry/index.cjs",
|
|
29
|
+
"import": "./dist/esm/modules/telemetry/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./schemas": {
|
|
32
|
+
"types": "./dist/types/modules/schemas/index.d.ts",
|
|
33
|
+
"require": "./dist/cjs/modules/schemas/index.cjs",
|
|
34
|
+
"import": "./dist/esm/modules/schemas/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./cronjobs": {
|
|
37
|
+
"types": "./dist/types/modules/cronjobs/index.d.ts",
|
|
38
|
+
"require": "./dist/cjs/modules/cronjobs/index.cjs",
|
|
39
|
+
"import": "./dist/esm/modules/cronjobs/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./jwt": {
|
|
42
|
+
"types": "./dist/types/modules/jwt/index.d.ts",
|
|
43
|
+
"require": "./dist/cjs/modules/jwt/index.cjs",
|
|
44
|
+
"import": "./dist/esm/modules/jwt/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./utils": {
|
|
47
|
+
"types": "./dist/types/modules/utils/index.d.ts",
|
|
48
|
+
"require": "./dist/cjs/modules/utils/index.cjs",
|
|
49
|
+
"import": "./dist/esm/modules/utils/index.js"
|
|
50
|
+
}
|
|
15
51
|
},
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
52
|
+
"files": [
|
|
53
|
+
"dist/**/*",
|
|
54
|
+
"README.md",
|
|
55
|
+
"LICENSE"
|
|
56
|
+
],
|
|
57
|
+
"scripts": {
|
|
58
|
+
"clean": "rimraf dist",
|
|
59
|
+
"build": "vite build && node -e \"const fs=require('fs');const p='dist/esm/cli.js';let c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c)}\"",
|
|
60
|
+
"dev": "NODE_ENV=development ts-node src/index.ts",
|
|
61
|
+
"start": "NODE_ENV=production ts-node src/index.ts",
|
|
62
|
+
"prepublishOnly": "npm run build",
|
|
63
|
+
"test": "jest",
|
|
64
|
+
"dev:example": "npm run build && node example/app.js"
|
|
20
65
|
},
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
"require": "./dist/cjs/modules/rate-limit/index.cjs",
|
|
24
|
-
"import": "./dist/esm/modules/rate-limit/index.js"
|
|
66
|
+
"repository": {
|
|
67
|
+
"url": "https://github.com/TPEOficial/sprint"
|
|
25
68
|
},
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
69
|
+
"keywords": [
|
|
70
|
+
"express",
|
|
71
|
+
"api",
|
|
72
|
+
"sprint",
|
|
73
|
+
"rate-limit"
|
|
74
|
+
],
|
|
75
|
+
"author": "TPEOficial LLC",
|
|
76
|
+
"license": "Apache-2.0",
|
|
77
|
+
"bugs": {
|
|
78
|
+
"url": "https://github.com/TPEOficial/sprint/issues"
|
|
30
79
|
},
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
80
|
+
"homepage": "https://dymo.tpeoficial.com",
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"axios": "^1.13.2",
|
|
83
|
+
"cors": "^2.8.5",
|
|
84
|
+
"dotenv": "^17.3.1",
|
|
85
|
+
"express": "^5.1.0",
|
|
86
|
+
"morgan": "^1.10.1",
|
|
87
|
+
"node-cron": "^3.0.3",
|
|
88
|
+
"path": "^0.12.7",
|
|
89
|
+
"serve-favicon": "^2.5.1",
|
|
90
|
+
"toolkitify": "^0.0.26",
|
|
91
|
+
"tsx": "^4.19.0",
|
|
92
|
+
"zod": "^3.25.0"
|
|
35
93
|
},
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
94
|
+
"contributors": [
|
|
95
|
+
"TPEOficial (https://github.com/TPEOficial)",
|
|
96
|
+
"FJRG2007 (https://github.com/FJRG2007)"
|
|
97
|
+
],
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@types/cors": "^2.8.19",
|
|
100
|
+
"@types/express": "^5.0.5",
|
|
101
|
+
"@types/jest": "^30.0.0",
|
|
102
|
+
"@types/morgan": "^1.9.10",
|
|
103
|
+
"@types/node": "^22.18.7",
|
|
104
|
+
"@types/node-cron": "^3.0.11",
|
|
105
|
+
"@types/serve-favicon": "^2.5.7",
|
|
106
|
+
"@types/swagger-ui-express": "^4.1.8",
|
|
107
|
+
"jest": "^30.1.3",
|
|
108
|
+
"rimraf": "^6.0.1",
|
|
109
|
+
"ts-jest": "^29.4.4",
|
|
110
|
+
"ts-node": "^10.9.2",
|
|
111
|
+
"typescript": "^5.5.4",
|
|
112
|
+
"vite": "^6.4.1",
|
|
113
|
+
"vite-plugin-dts": "^4.5.4"
|
|
40
114
|
},
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
"require": "./dist/cjs/modules/jwt/index.cjs",
|
|
44
|
-
"import": "./dist/esm/modules/jwt/index.js"
|
|
115
|
+
"optionalDependencies": {
|
|
116
|
+
"swagger-ui-express": "^5.0.1"
|
|
45
117
|
},
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"import": "./dist/esm/modules/utils/index.js"
|
|
118
|
+
"prettier": {
|
|
119
|
+
"tabWidth": 4,
|
|
120
|
+
"useTabs": false
|
|
50
121
|
}
|
|
51
|
-
},
|
|
52
|
-
"files": [
|
|
53
|
-
"dist/**/*",
|
|
54
|
-
"README.md",
|
|
55
|
-
"LICENSE"
|
|
56
|
-
],
|
|
57
|
-
"scripts": {
|
|
58
|
-
"clean": "rimraf dist",
|
|
59
|
-
"build": "vite build && node -e \"const fs=require('fs');const p='dist/esm/cli.js';let c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c)}\"",
|
|
60
|
-
"dev": "NODE_ENV=development ts-node src/index.ts",
|
|
61
|
-
"start": "NODE_ENV=production ts-node src/index.ts",
|
|
62
|
-
"prepublishOnly": "npm run build",
|
|
63
|
-
"test": "jest",
|
|
64
|
-
"dev:example": "npm run build && node example/app.js"
|
|
65
|
-
},
|
|
66
|
-
"repository": {
|
|
67
|
-
"url": "https://github.com/TPEOficial/sprint"
|
|
68
|
-
},
|
|
69
|
-
"keywords": [
|
|
70
|
-
"express",
|
|
71
|
-
"api",
|
|
72
|
-
"sprint",
|
|
73
|
-
"rate-limit"
|
|
74
|
-
],
|
|
75
|
-
"author": "TPEOficial LLC",
|
|
76
|
-
"license": "Apache-2.0",
|
|
77
|
-
"bugs": {
|
|
78
|
-
"url": "https://github.com/TPEOficial/sprint/issues"
|
|
79
|
-
},
|
|
80
|
-
"homepage": "https://dymo.tpeoficial.com",
|
|
81
|
-
"dependencies": {
|
|
82
|
-
"axios": "^1.13.2",
|
|
83
|
-
"cors": "^2.8.5",
|
|
84
|
-
"dotenv": "^17.3.1",
|
|
85
|
-
"express": "^5.1.0",
|
|
86
|
-
"morgan": "^1.10.1",
|
|
87
|
-
"node-cron": "^3.0.3",
|
|
88
|
-
"path": "^0.12.7",
|
|
89
|
-
"serve-favicon": "^2.5.1",
|
|
90
|
-
"toolkitify": "^0.0.26",
|
|
91
|
-
"tsx": "^4.19.0",
|
|
92
|
-
"zod": "^3.25.0"
|
|
93
|
-
},
|
|
94
|
-
"contributors": [
|
|
95
|
-
"TPEOficial (https://github.com/TPEOficial)",
|
|
96
|
-
"FJRG2007 (https://github.com/FJRG2007)"
|
|
97
|
-
],
|
|
98
|
-
"devDependencies": {
|
|
99
|
-
"@types/cors": "^2.8.19",
|
|
100
|
-
"@types/express": "^5.0.5",
|
|
101
|
-
"@types/jest": "^30.0.0",
|
|
102
|
-
"@types/morgan": "^1.9.10",
|
|
103
|
-
"@types/node": "^22.18.7",
|
|
104
|
-
"@types/node-cron": "^3.0.11",
|
|
105
|
-
"@types/serve-favicon": "^2.5.7",
|
|
106
|
-
"@types/swagger-ui-express": "^4.1.8",
|
|
107
|
-
"jest": "^30.1.3",
|
|
108
|
-
"rimraf": "^6.0.1",
|
|
109
|
-
"ts-jest": "^29.4.4",
|
|
110
|
-
"ts-node": "^10.9.2",
|
|
111
|
-
"typescript": "^5.5.4",
|
|
112
|
-
"vite": "^6.4.1",
|
|
113
|
-
"vite-plugin-dts": "^4.5.4"
|
|
114
|
-
},
|
|
115
|
-
"optionalDependencies": {
|
|
116
|
-
"swagger-ui-express": "^5.0.1"
|
|
117
|
-
},
|
|
118
|
-
"prettier": {
|
|
119
|
-
"tabWidth": 4,
|
|
120
|
-
"useTabs": false
|
|
121
|
-
}
|
|
122
122
|
}
|