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.
@@ -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, swaggerUi.setup(void 0, {
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 && zod) {
443
+ if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
449
444
  try {
450
- routeSpec.requestBody = {
451
- content: {
452
- "application/json": {
453
- schema: route.schema.body.schema || route.schema.body._def?.schema?.toJSON?.() || {}
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 && zod) {
459
+ if (route.schema?.queryParams) {
461
460
  try {
462
- routeSpec.parameters = [];
463
- const querySchema = route.schema.queryParams.schema || route.schema.queryParams._def?.schema;
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, swaggerUi.setup(void 0, {
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 && zod) {
418
+ if (route.schema?.body && !["GET", "HEAD", "DELETE"].includes(route.method)) {
424
419
  try {
425
- routeSpec.requestBody = {
426
- content: {
427
- "application/json": {
428
- schema: route.schema.body.schema || route.schema.body._def?.schema?.toJSON?.() || {}
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 && zod) {
434
+ if (route.schema?.queryParams) {
436
435
  try {
437
- routeSpec.parameters = [];
438
- const querySchema = route.schema.queryParams.schema || route.schema.queryParams._def?.schema;
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);
@@ -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;;YAuEM,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;IAyEpB,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;;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprint-es",
3
- "version": "0.0.65",
3
+ "version": "0.0.67",
4
4
  "description": "Sprint - Quickly API",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",