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.
@@ -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
- }).catch(() => {
175
- console.error(`[Sprint] ⚠️ swagger-ui-express is not installed. Run "npm install swagger-ui-express" to enable Swagger UI.`);
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
- paths[route.path][method] = {
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
- }).catch(() => {
150
- console.error(`[Sprint] ⚠️ swagger-ui-express is not installed. Run "npm install swagger-ui-express" to enable Swagger UI.`);
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
- paths[route.path][method] = {
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);
@@ -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;;YAoEM,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;IA6BpB,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.63",
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",