sprint-es 0.0.65 → 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.
@@ -163,9 +163,6 @@ 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) => {
@@ -178,6 +175,9 @@ class Sprint {
178
175
  console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
179
176
  });
180
177
  }
178
+ this.app.get("/openapi.json", (_, res) => {
179
+ res.json(this.generateOpenAPISpec());
180
+ });
181
181
  }
182
182
  if (finalConfig.autoListen) this.listen();
183
183
  });
@@ -428,12 +428,6 @@ class Sprint {
428
428
  }
429
429
  generateOpenAPISpec() {
430
430
  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
431
  for (const route of this.registeredRoutes || []) {
438
432
  const method = route.method.toLowerCase();
439
433
  if (!paths[route.path]) paths[route.path] = {};
@@ -445,33 +439,30 @@ class Sprint {
445
439
  }
446
440
  }
447
441
  };
448
- if (route.schema?.body && zod) {
442
+ if (route.schema?.body) {
449
443
  try {
450
- routeSpec.requestBody = {
451
- content: {
452
- "application/json": {
453
- schema: route.schema.body.schema || route.schema.body._def?.schema?.toJSON?.() || {}
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
+ }
454
451
  }
455
- }
456
- };
452
+ };
453
+ }
457
454
  } catch (e) {
455
+ console.warn("[Sprint] Failed to convert body schema:", e);
458
456
  }
459
457
  }
460
- if (route.schema?.queryParams && zod) {
458
+ if (route.schema?.queryParams) {
461
459
  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
- }
460
+ const params = this.zodParamsToOpenAPI(route.schema.queryParams);
461
+ if (params.length > 0) {
462
+ routeSpec.parameters = params;
473
463
  }
474
464
  } catch (e) {
465
+ console.warn("[Sprint] Failed to convert query params schema:", e);
475
466
  }
476
467
  }
477
468
  paths[route.path][method] = routeSpec;
@@ -485,6 +476,68 @@ class Sprint {
485
476
  paths
486
477
  };
487
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
+ }
488
541
  // HTTP Methods (prefix is applied automatically).
489
542
  get(path2, handler) {
490
543
  return this.app.get(this.applyPrefix(path2), handler);
package/dist/esm/index.js CHANGED
@@ -138,9 +138,6 @@ 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) => {
@@ -153,6 +150,9 @@ class Sprint {
153
150
  console.error(`[Sprint] ⚠️ swagger-ui-express error:`, err);
154
151
  });
155
152
  }
153
+ this.app.get("/openapi.json", (_, res) => {
154
+ res.json(this.generateOpenAPISpec());
155
+ });
156
156
  }
157
157
  if (finalConfig.autoListen) this.listen();
158
158
  });
@@ -403,12 +403,6 @@ class Sprint {
403
403
  }
404
404
  generateOpenAPISpec() {
405
405
  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
406
  for (const route of this.registeredRoutes || []) {
413
407
  const method = route.method.toLowerCase();
414
408
  if (!paths[route.path]) paths[route.path] = {};
@@ -420,33 +414,30 @@ class Sprint {
420
414
  }
421
415
  }
422
416
  };
423
- if (route.schema?.body && zod) {
417
+ if (route.schema?.body) {
424
418
  try {
425
- routeSpec.requestBody = {
426
- content: {
427
- "application/json": {
428
- schema: route.schema.body.schema || route.schema.body._def?.schema?.toJSON?.() || {}
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
+ }
429
426
  }
430
- }
431
- };
427
+ };
428
+ }
432
429
  } catch (e) {
430
+ console.warn("[Sprint] Failed to convert body schema:", e);
433
431
  }
434
432
  }
435
- if (route.schema?.queryParams && zod) {
433
+ if (route.schema?.queryParams) {
436
434
  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
- }
435
+ const params = this.zodParamsToOpenAPI(route.schema.queryParams);
436
+ if (params.length > 0) {
437
+ routeSpec.parameters = params;
448
438
  }
449
439
  } catch (e) {
440
+ console.warn("[Sprint] Failed to convert query params schema:", e);
450
441
  }
451
442
  }
452
443
  paths[route.path][method] = routeSpec;
@@ -460,6 +451,68 @@ class Sprint {
460
451
  paths
461
452
  };
462
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
+ }
463
516
  // HTTP Methods (prefix is applied automatically).
464
517
  get(path2, handler) {
465
518
  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;;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprint-es",
3
- "version": "0.0.65",
3
+ "version": "0.0.66",
4
4
  "description": "Sprint - Quickly API",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",