sprint-es 0.0.65 → 0.0.67
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 +82 -30
- package/dist/esm/index.js +82 -30
- package/dist/types/sprint.d.ts +2 -0
- package/dist/types/sprint.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -163,14 +163,12 @@ class Sprint {
|
|
|
163
163
|
this.routesLoaded = this.init();
|
|
164
164
|
this.routesLoaded.then(() => {
|
|
165
165
|
if (this.openapi.generateOnBuild) {
|
|
166
|
-
this.app.get("/openapi.json", (_, res) => {
|
|
167
|
-
res.json(this.generateOpenAPISpec());
|
|
168
|
-
});
|
|
169
166
|
if (this.openapi.swaggerUi.enabled) {
|
|
170
167
|
console.log(`[Sprint] Loading Swagger UI...`);
|
|
171
168
|
import("swagger-ui-express").then((swaggerUi) => {
|
|
172
169
|
console.log(`[Sprint] Swagger UI imported successfully`);
|
|
173
|
-
this.app.use("/swagger", swaggerUi.serve
|
|
170
|
+
this.app.use("/swagger", swaggerUi.serve);
|
|
171
|
+
this.app.use("/swagger", swaggerUi.setup(void 0, {
|
|
174
172
|
swaggerUrl: "/openapi.json"
|
|
175
173
|
}));
|
|
176
174
|
console.log(`[Sprint] Swagger UI mounted at /swagger`);
|
|
@@ -178,6 +176,9 @@ class Sprint {
|
|
|
178
176
|
console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
|
|
179
177
|
});
|
|
180
178
|
}
|
|
179
|
+
this.app.get("/openapi.json", (_, res) => {
|
|
180
|
+
res.json(this.generateOpenAPISpec());
|
|
181
|
+
});
|
|
181
182
|
}
|
|
182
183
|
if (finalConfig.autoListen) this.listen();
|
|
183
184
|
});
|
|
@@ -428,12 +429,6 @@ class Sprint {
|
|
|
428
429
|
}
|
|
429
430
|
generateOpenAPISpec() {
|
|
430
431
|
const paths = {};
|
|
431
|
-
let zod;
|
|
432
|
-
try {
|
|
433
|
-
zod = require("zod");
|
|
434
|
-
} catch (e) {
|
|
435
|
-
console.warn("[Sprint] Zod not available for OpenAPI schema generation");
|
|
436
|
-
}
|
|
437
432
|
for (const route of this.registeredRoutes || []) {
|
|
438
433
|
const method = route.method.toLowerCase();
|
|
439
434
|
if (!paths[route.path]) paths[route.path] = {};
|
|
@@ -445,33 +440,28 @@ class Sprint {
|
|
|
445
440
|
}
|
|
446
441
|
}
|
|
447
442
|
};
|
|
448
|
-
if (route.schema?.body &&
|
|
443
|
+
if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
|
|
449
444
|
try {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
445
|
+
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
446
|
+
if (Object.keys(bodySchema).length > 0) {
|
|
447
|
+
routeSpec.requestBody = {
|
|
448
|
+
content: {
|
|
449
|
+
"application/json": {
|
|
450
|
+
schema: bodySchema
|
|
451
|
+
}
|
|
454
452
|
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
457
455
|
} catch (e) {
|
|
456
|
+
console.warn("[Sprint] Failed to convert body schema:", e);
|
|
458
457
|
}
|
|
459
458
|
}
|
|
460
|
-
if (route.schema?.queryParams
|
|
459
|
+
if (route.schema?.queryParams) {
|
|
461
460
|
try {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (querySchema?.shape) {
|
|
465
|
-
for (const [key, value] of Object.entries(querySchema.shape)) {
|
|
466
|
-
routeSpec.parameters.push({
|
|
467
|
-
name: key,
|
|
468
|
-
in: "query",
|
|
469
|
-
required: !value.isOptional?.(),
|
|
470
|
-
schema: value._def?.typeName ? { type: "string" } : {}
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
461
|
+
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
462
|
+
if (params.length > 0) routeSpec.parameters = params;
|
|
474
463
|
} catch (e) {
|
|
464
|
+
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
475
465
|
}
|
|
476
466
|
}
|
|
477
467
|
paths[route.path][method] = routeSpec;
|
|
@@ -485,6 +475,68 @@ class Sprint {
|
|
|
485
475
|
paths
|
|
486
476
|
};
|
|
487
477
|
}
|
|
478
|
+
zodSchemaToOpenAPI(schema) {
|
|
479
|
+
if (!schema) return {};
|
|
480
|
+
if (schema._def?.typeName === "ZodObject" || schema.shape) {
|
|
481
|
+
const shape = schema.shape || schema._def?.shape();
|
|
482
|
+
if (!shape) return {};
|
|
483
|
+
const properties = {};
|
|
484
|
+
const required = [];
|
|
485
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
486
|
+
const zodDef = value._def;
|
|
487
|
+
const typeName = zodDef?.typeName;
|
|
488
|
+
let propSchema = {};
|
|
489
|
+
if (typeName === "ZodString") {
|
|
490
|
+
propSchema = { type: "string" };
|
|
491
|
+
} else if (typeName === "ZodNumber") {
|
|
492
|
+
propSchema = { type: "number" };
|
|
493
|
+
} else if (typeName === "ZodBoolean") {
|
|
494
|
+
propSchema = { type: "boolean" };
|
|
495
|
+
} else if (typeName === "ZodArray") {
|
|
496
|
+
propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
|
|
497
|
+
} else if (typeName === "ZodObject") {
|
|
498
|
+
propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
|
|
499
|
+
} else if (typeName === "ZodOptional") {
|
|
500
|
+
continue;
|
|
501
|
+
} else {
|
|
502
|
+
propSchema = { type: "string" };
|
|
503
|
+
}
|
|
504
|
+
properties[key] = propSchema;
|
|
505
|
+
if (!zodDef?.isOptional && typeName !== "ZodOptional") {
|
|
506
|
+
required.push(key);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return { type: "object", properties, required: required.length > 0 ? required : void 0 };
|
|
510
|
+
}
|
|
511
|
+
return {};
|
|
512
|
+
}
|
|
513
|
+
zodParamsToOpenAPI(schema) {
|
|
514
|
+
if (!schema) return [];
|
|
515
|
+
const params = [];
|
|
516
|
+
const shape = schema.shape || schema._def?.shape();
|
|
517
|
+
if (!shape) return [];
|
|
518
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
519
|
+
const zodDef = value._def;
|
|
520
|
+
const typeName = zodDef?.typeName;
|
|
521
|
+
let paramSchema = {};
|
|
522
|
+
if (typeName === "ZodString") {
|
|
523
|
+
paramSchema = { type: "string" };
|
|
524
|
+
} else if (typeName === "ZodNumber") {
|
|
525
|
+
paramSchema = { type: "number" };
|
|
526
|
+
} else if (typeName === "ZodBoolean") {
|
|
527
|
+
paramSchema = { type: "boolean" };
|
|
528
|
+
} else {
|
|
529
|
+
paramSchema = { type: "string" };
|
|
530
|
+
}
|
|
531
|
+
params.push({
|
|
532
|
+
name: key,
|
|
533
|
+
in: "query",
|
|
534
|
+
required: !zodDef?.isOptional,
|
|
535
|
+
schema: paramSchema
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
return params;
|
|
539
|
+
}
|
|
488
540
|
// HTTP Methods (prefix is applied automatically).
|
|
489
541
|
get(path2, handler) {
|
|
490
542
|
return this.app.get(this.applyPrefix(path2), handler);
|
package/dist/esm/index.js
CHANGED
|
@@ -138,14 +138,12 @@ class Sprint {
|
|
|
138
138
|
this.routesLoaded = this.init();
|
|
139
139
|
this.routesLoaded.then(() => {
|
|
140
140
|
if (this.openapi.generateOnBuild) {
|
|
141
|
-
this.app.get("/openapi.json", (_, res) => {
|
|
142
|
-
res.json(this.generateOpenAPISpec());
|
|
143
|
-
});
|
|
144
141
|
if (this.openapi.swaggerUi.enabled) {
|
|
145
142
|
console.log(`[Sprint] Loading Swagger UI...`);
|
|
146
143
|
import("swagger-ui-express").then((swaggerUi) => {
|
|
147
144
|
console.log(`[Sprint] Swagger UI imported successfully`);
|
|
148
|
-
this.app.use("/swagger", swaggerUi.serve
|
|
145
|
+
this.app.use("/swagger", swaggerUi.serve);
|
|
146
|
+
this.app.use("/swagger", swaggerUi.setup(void 0, {
|
|
149
147
|
swaggerUrl: "/openapi.json"
|
|
150
148
|
}));
|
|
151
149
|
console.log(`[Sprint] Swagger UI mounted at /swagger`);
|
|
@@ -153,6 +151,9 @@ class Sprint {
|
|
|
153
151
|
console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
|
|
154
152
|
});
|
|
155
153
|
}
|
|
154
|
+
this.app.get("/openapi.json", (_, res) => {
|
|
155
|
+
res.json(this.generateOpenAPISpec());
|
|
156
|
+
});
|
|
156
157
|
}
|
|
157
158
|
if (finalConfig.autoListen) this.listen();
|
|
158
159
|
});
|
|
@@ -403,12 +404,6 @@ class Sprint {
|
|
|
403
404
|
}
|
|
404
405
|
generateOpenAPISpec() {
|
|
405
406
|
const paths = {};
|
|
406
|
-
let zod;
|
|
407
|
-
try {
|
|
408
|
-
zod = require("zod");
|
|
409
|
-
} catch (e) {
|
|
410
|
-
console.warn("[Sprint] Zod not available for OpenAPI schema generation");
|
|
411
|
-
}
|
|
412
407
|
for (const route of this.registeredRoutes || []) {
|
|
413
408
|
const method = route.method.toLowerCase();
|
|
414
409
|
if (!paths[route.path]) paths[route.path] = {};
|
|
@@ -420,33 +415,28 @@ class Sprint {
|
|
|
420
415
|
}
|
|
421
416
|
}
|
|
422
417
|
};
|
|
423
|
-
if (route.schema?.body &&
|
|
418
|
+
if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
|
|
424
419
|
try {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
420
|
+
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
421
|
+
if (Object.keys(bodySchema).length > 0) {
|
|
422
|
+
routeSpec.requestBody = {
|
|
423
|
+
content: {
|
|
424
|
+
"application/json": {
|
|
425
|
+
schema: bodySchema
|
|
426
|
+
}
|
|
429
427
|
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
432
430
|
} catch (e) {
|
|
431
|
+
console.warn("[Sprint] Failed to convert body schema:", e);
|
|
433
432
|
}
|
|
434
433
|
}
|
|
435
|
-
if (route.schema?.queryParams
|
|
434
|
+
if (route.schema?.queryParams) {
|
|
436
435
|
try {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (querySchema?.shape) {
|
|
440
|
-
for (const [key, value] of Object.entries(querySchema.shape)) {
|
|
441
|
-
routeSpec.parameters.push({
|
|
442
|
-
name: key,
|
|
443
|
-
in: "query",
|
|
444
|
-
required: !value.isOptional?.(),
|
|
445
|
-
schema: value._def?.typeName ? { type: "string" } : {}
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
436
|
+
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
437
|
+
if (params.length > 0) routeSpec.parameters = params;
|
|
449
438
|
} catch (e) {
|
|
439
|
+
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
450
440
|
}
|
|
451
441
|
}
|
|
452
442
|
paths[route.path][method] = routeSpec;
|
|
@@ -460,6 +450,68 @@ class Sprint {
|
|
|
460
450
|
paths
|
|
461
451
|
};
|
|
462
452
|
}
|
|
453
|
+
zodSchemaToOpenAPI(schema) {
|
|
454
|
+
if (!schema) return {};
|
|
455
|
+
if (schema._def?.typeName === "ZodObject" || schema.shape) {
|
|
456
|
+
const shape = schema.shape || schema._def?.shape();
|
|
457
|
+
if (!shape) return {};
|
|
458
|
+
const properties = {};
|
|
459
|
+
const required = [];
|
|
460
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
461
|
+
const zodDef = value._def;
|
|
462
|
+
const typeName = zodDef?.typeName;
|
|
463
|
+
let propSchema = {};
|
|
464
|
+
if (typeName === "ZodString") {
|
|
465
|
+
propSchema = { type: "string" };
|
|
466
|
+
} else if (typeName === "ZodNumber") {
|
|
467
|
+
propSchema = { type: "number" };
|
|
468
|
+
} else if (typeName === "ZodBoolean") {
|
|
469
|
+
propSchema = { type: "boolean" };
|
|
470
|
+
} else if (typeName === "ZodArray") {
|
|
471
|
+
propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
|
|
472
|
+
} else if (typeName === "ZodObject") {
|
|
473
|
+
propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
|
|
474
|
+
} else if (typeName === "ZodOptional") {
|
|
475
|
+
continue;
|
|
476
|
+
} else {
|
|
477
|
+
propSchema = { type: "string" };
|
|
478
|
+
}
|
|
479
|
+
properties[key] = propSchema;
|
|
480
|
+
if (!zodDef?.isOptional && typeName !== "ZodOptional") {
|
|
481
|
+
required.push(key);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return { type: "object", properties, required: required.length > 0 ? required : void 0 };
|
|
485
|
+
}
|
|
486
|
+
return {};
|
|
487
|
+
}
|
|
488
|
+
zodParamsToOpenAPI(schema) {
|
|
489
|
+
if (!schema) return [];
|
|
490
|
+
const params = [];
|
|
491
|
+
const shape = schema.shape || schema._def?.shape();
|
|
492
|
+
if (!shape) return [];
|
|
493
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
494
|
+
const zodDef = value._def;
|
|
495
|
+
const typeName = zodDef?.typeName;
|
|
496
|
+
let paramSchema = {};
|
|
497
|
+
if (typeName === "ZodString") {
|
|
498
|
+
paramSchema = { type: "string" };
|
|
499
|
+
} else if (typeName === "ZodNumber") {
|
|
500
|
+
paramSchema = { type: "number" };
|
|
501
|
+
} else if (typeName === "ZodBoolean") {
|
|
502
|
+
paramSchema = { type: "boolean" };
|
|
503
|
+
} else {
|
|
504
|
+
paramSchema = { type: "string" };
|
|
505
|
+
}
|
|
506
|
+
params.push({
|
|
507
|
+
name: key,
|
|
508
|
+
in: "query",
|
|
509
|
+
required: !zodDef?.isOptional,
|
|
510
|
+
schema: paramSchema
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
return params;
|
|
514
|
+
}
|
|
463
515
|
// HTTP Methods (prefix is applied automatically).
|
|
464
516
|
get(path2, handler) {
|
|
465
517
|
return this.app.get(this.applyPrefix(path2), handler);
|
package/dist/types/sprint.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export declare class Sprint {
|
|
|
34
34
|
/** Applies prefix to a path */
|
|
35
35
|
private applyPrefix;
|
|
36
36
|
private generateOpenAPISpec;
|
|
37
|
+
private zodSchemaToOpenAPI;
|
|
38
|
+
private zodParamsToOpenAPI;
|
|
37
39
|
get(path: string, handler: Handler): express.Application;
|
|
38
40
|
post(path: string, handler: Handler): express.Application;
|
|
39
41
|
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;;YAyEM,IAAI;IAkClB,OAAO,CAAC,YAAY;IAiDpB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA4B9B;;OAEG;YACW,eAAe;IAgC7B,OAAO,CAAC,eAAe;YAcT,UAAU;YAoFV,YAAY;IAmB1B,OAAO,CAAC,YAAY;IAgCpB,+BAA+B;IAC/B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,mBAAmB;IA2D3B,OAAO,CAAC,kBAAkB;IAgD1B,OAAO,CAAC,kBAAkB;IAoCnB,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"}
|