sprint-es 0.0.63 → 0.0.66
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 +98 -6
- package/dist/esm/index.js +98 -6
- 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,18 +163,21 @@ 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) {
|
|
167
|
+
console.log(`[Sprint] Loading Swagger UI...`);
|
|
170
168
|
import("swagger-ui-express").then((swaggerUi) => {
|
|
169
|
+
console.log(`[Sprint] Swagger UI imported successfully`);
|
|
171
170
|
this.app.use("/swagger", swaggerUi.serve, swaggerUi.setup(void 0, {
|
|
172
171
|
swaggerUrl: "/openapi.json"
|
|
173
172
|
}));
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
console.log(`[Sprint] Swagger UI mounted at /swagger`);
|
|
174
|
+
}).catch((err) => {
|
|
175
|
+
console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
|
+
this.app.get("/openapi.json", (_, res) => {
|
|
179
|
+
res.json(this.generateOpenAPISpec());
|
|
180
|
+
});
|
|
178
181
|
}
|
|
179
182
|
if (finalConfig.autoListen) this.listen();
|
|
180
183
|
});
|
|
@@ -428,7 +431,7 @@ class Sprint {
|
|
|
428
431
|
for (const route of this.registeredRoutes || []) {
|
|
429
432
|
const method = route.method.toLowerCase();
|
|
430
433
|
if (!paths[route.path]) paths[route.path] = {};
|
|
431
|
-
|
|
434
|
+
const routeSpec = {
|
|
432
435
|
summary: "Auto generated by Sprint",
|
|
433
436
|
responses: {
|
|
434
437
|
"200": {
|
|
@@ -436,6 +439,33 @@ class Sprint {
|
|
|
436
439
|
}
|
|
437
440
|
}
|
|
438
441
|
};
|
|
442
|
+
if (route.schema?.body) {
|
|
443
|
+
try {
|
|
444
|
+
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
445
|
+
if (Object.keys(bodySchema).length > 0) {
|
|
446
|
+
routeSpec.requestBody = {
|
|
447
|
+
content: {
|
|
448
|
+
"application/json": {
|
|
449
|
+
schema: bodySchema
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
} catch (e) {
|
|
455
|
+
console.warn("[Sprint] Failed to convert body schema:", e);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (route.schema?.queryParams) {
|
|
459
|
+
try {
|
|
460
|
+
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
461
|
+
if (params.length > 0) {
|
|
462
|
+
routeSpec.parameters = params;
|
|
463
|
+
}
|
|
464
|
+
} catch (e) {
|
|
465
|
+
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
paths[route.path][method] = routeSpec;
|
|
439
469
|
}
|
|
440
470
|
return {
|
|
441
471
|
openapi: "3.0.0",
|
|
@@ -446,6 +476,68 @@ class Sprint {
|
|
|
446
476
|
paths
|
|
447
477
|
};
|
|
448
478
|
}
|
|
479
|
+
zodSchemaToOpenAPI(schema) {
|
|
480
|
+
if (!schema) return {};
|
|
481
|
+
if (schema._def?.typeName === "ZodObject" || schema.shape) {
|
|
482
|
+
const shape = schema.shape || schema._def?.shape();
|
|
483
|
+
if (!shape) return {};
|
|
484
|
+
const properties = {};
|
|
485
|
+
const required = [];
|
|
486
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
487
|
+
const zodDef = value._def;
|
|
488
|
+
const typeName = zodDef?.typeName;
|
|
489
|
+
let propSchema = {};
|
|
490
|
+
if (typeName === "ZodString") {
|
|
491
|
+
propSchema = { type: "string" };
|
|
492
|
+
} else if (typeName === "ZodNumber") {
|
|
493
|
+
propSchema = { type: "number" };
|
|
494
|
+
} else if (typeName === "ZodBoolean") {
|
|
495
|
+
propSchema = { type: "boolean" };
|
|
496
|
+
} else if (typeName === "ZodArray") {
|
|
497
|
+
propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
|
|
498
|
+
} else if (typeName === "ZodObject") {
|
|
499
|
+
propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
|
|
500
|
+
} else if (typeName === "ZodOptional") {
|
|
501
|
+
continue;
|
|
502
|
+
} else {
|
|
503
|
+
propSchema = { type: "string" };
|
|
504
|
+
}
|
|
505
|
+
properties[key] = propSchema;
|
|
506
|
+
if (!zodDef?.isOptional && typeName !== "ZodOptional") {
|
|
507
|
+
required.push(key);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return { type: "object", properties, required: required.length > 0 ? required : void 0 };
|
|
511
|
+
}
|
|
512
|
+
return {};
|
|
513
|
+
}
|
|
514
|
+
zodParamsToOpenAPI(schema) {
|
|
515
|
+
if (!schema) return [];
|
|
516
|
+
const params = [];
|
|
517
|
+
const shape = schema.shape || schema._def?.shape();
|
|
518
|
+
if (!shape) return [];
|
|
519
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
520
|
+
const zodDef = value._def;
|
|
521
|
+
const typeName = zodDef?.typeName;
|
|
522
|
+
let paramSchema = {};
|
|
523
|
+
if (typeName === "ZodString") {
|
|
524
|
+
paramSchema = { type: "string" };
|
|
525
|
+
} else if (typeName === "ZodNumber") {
|
|
526
|
+
paramSchema = { type: "number" };
|
|
527
|
+
} else if (typeName === "ZodBoolean") {
|
|
528
|
+
paramSchema = { type: "boolean" };
|
|
529
|
+
} else {
|
|
530
|
+
paramSchema = { type: "string" };
|
|
531
|
+
}
|
|
532
|
+
params.push({
|
|
533
|
+
name: key,
|
|
534
|
+
in: "query",
|
|
535
|
+
required: !zodDef?.isOptional,
|
|
536
|
+
schema: paramSchema
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
return params;
|
|
540
|
+
}
|
|
449
541
|
// HTTP Methods (prefix is applied automatically).
|
|
450
542
|
get(path2, handler) {
|
|
451
543
|
return this.app.get(this.applyPrefix(path2), handler);
|
package/dist/esm/index.js
CHANGED
|
@@ -138,18 +138,21 @@ 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) {
|
|
142
|
+
console.log(`[Sprint] Loading Swagger UI...`);
|
|
145
143
|
import("swagger-ui-express").then((swaggerUi) => {
|
|
144
|
+
console.log(`[Sprint] Swagger UI imported successfully`);
|
|
146
145
|
this.app.use("/swagger", swaggerUi.serve, swaggerUi.setup(void 0, {
|
|
147
146
|
swaggerUrl: "/openapi.json"
|
|
148
147
|
}));
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
console.log(`[Sprint] Swagger UI mounted at /swagger`);
|
|
149
|
+
}).catch((err) => {
|
|
150
|
+
console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
+
this.app.get("/openapi.json", (_, res) => {
|
|
154
|
+
res.json(this.generateOpenAPISpec());
|
|
155
|
+
});
|
|
153
156
|
}
|
|
154
157
|
if (finalConfig.autoListen) this.listen();
|
|
155
158
|
});
|
|
@@ -403,7 +406,7 @@ class Sprint {
|
|
|
403
406
|
for (const route of this.registeredRoutes || []) {
|
|
404
407
|
const method = route.method.toLowerCase();
|
|
405
408
|
if (!paths[route.path]) paths[route.path] = {};
|
|
406
|
-
|
|
409
|
+
const routeSpec = {
|
|
407
410
|
summary: "Auto generated by Sprint",
|
|
408
411
|
responses: {
|
|
409
412
|
"200": {
|
|
@@ -411,6 +414,33 @@ class Sprint {
|
|
|
411
414
|
}
|
|
412
415
|
}
|
|
413
416
|
};
|
|
417
|
+
if (route.schema?.body) {
|
|
418
|
+
try {
|
|
419
|
+
const bodySchema = this.zodSchemaToOpenAPI(route.schema.body);
|
|
420
|
+
if (Object.keys(bodySchema).length > 0) {
|
|
421
|
+
routeSpec.requestBody = {
|
|
422
|
+
content: {
|
|
423
|
+
"application/json": {
|
|
424
|
+
schema: bodySchema
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
} catch (e) {
|
|
430
|
+
console.warn("[Sprint] Failed to convert body schema:", e);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (route.schema?.queryParams) {
|
|
434
|
+
try {
|
|
435
|
+
const params = this.zodParamsToOpenAPI(route.schema.queryParams);
|
|
436
|
+
if (params.length > 0) {
|
|
437
|
+
routeSpec.parameters = params;
|
|
438
|
+
}
|
|
439
|
+
} catch (e) {
|
|
440
|
+
console.warn("[Sprint] Failed to convert query params schema:", e);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
paths[route.path][method] = routeSpec;
|
|
414
444
|
}
|
|
415
445
|
return {
|
|
416
446
|
openapi: "3.0.0",
|
|
@@ -421,6 +451,68 @@ class Sprint {
|
|
|
421
451
|
paths
|
|
422
452
|
};
|
|
423
453
|
}
|
|
454
|
+
zodSchemaToOpenAPI(schema) {
|
|
455
|
+
if (!schema) return {};
|
|
456
|
+
if (schema._def?.typeName === "ZodObject" || schema.shape) {
|
|
457
|
+
const shape = schema.shape || schema._def?.shape();
|
|
458
|
+
if (!shape) return {};
|
|
459
|
+
const properties = {};
|
|
460
|
+
const required = [];
|
|
461
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
462
|
+
const zodDef = value._def;
|
|
463
|
+
const typeName = zodDef?.typeName;
|
|
464
|
+
let propSchema = {};
|
|
465
|
+
if (typeName === "ZodString") {
|
|
466
|
+
propSchema = { type: "string" };
|
|
467
|
+
} else if (typeName === "ZodNumber") {
|
|
468
|
+
propSchema = { type: "number" };
|
|
469
|
+
} else if (typeName === "ZodBoolean") {
|
|
470
|
+
propSchema = { type: "boolean" };
|
|
471
|
+
} else if (typeName === "ZodArray") {
|
|
472
|
+
propSchema = { type: "array", items: this.zodSchemaToOpenAPI(zodDef?.type) };
|
|
473
|
+
} else if (typeName === "ZodObject") {
|
|
474
|
+
propSchema = this.zodSchemaToOpenAPI(zodDef?.type);
|
|
475
|
+
} else if (typeName === "ZodOptional") {
|
|
476
|
+
continue;
|
|
477
|
+
} else {
|
|
478
|
+
propSchema = { type: "string" };
|
|
479
|
+
}
|
|
480
|
+
properties[key] = propSchema;
|
|
481
|
+
if (!zodDef?.isOptional && typeName !== "ZodOptional") {
|
|
482
|
+
required.push(key);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return { type: "object", properties, required: required.length > 0 ? required : void 0 };
|
|
486
|
+
}
|
|
487
|
+
return {};
|
|
488
|
+
}
|
|
489
|
+
zodParamsToOpenAPI(schema) {
|
|
490
|
+
if (!schema) return [];
|
|
491
|
+
const params = [];
|
|
492
|
+
const shape = schema.shape || schema._def?.shape();
|
|
493
|
+
if (!shape) return [];
|
|
494
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
495
|
+
const zodDef = value._def;
|
|
496
|
+
const typeName = zodDef?.typeName;
|
|
497
|
+
let paramSchema = {};
|
|
498
|
+
if (typeName === "ZodString") {
|
|
499
|
+
paramSchema = { type: "string" };
|
|
500
|
+
} else if (typeName === "ZodNumber") {
|
|
501
|
+
paramSchema = { type: "number" };
|
|
502
|
+
} else if (typeName === "ZodBoolean") {
|
|
503
|
+
paramSchema = { type: "boolean" };
|
|
504
|
+
} else {
|
|
505
|
+
paramSchema = { type: "string" };
|
|
506
|
+
}
|
|
507
|
+
params.push({
|
|
508
|
+
name: key,
|
|
509
|
+
in: "query",
|
|
510
|
+
required: !zodDef?.isOptional,
|
|
511
|
+
schema: paramSchema
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
return params;
|
|
515
|
+
}
|
|
424
516
|
// HTTP Methods (prefix is applied automatically).
|
|
425
517
|
get(path2, handler) {
|
|
426
518
|
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;;YAwEM,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;IA4D3B,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"}
|