@tahminator/sapling 2.0.4 → 2.0.5-beta.18e683d9

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/index.cjs CHANGED
@@ -23,6 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let express = require("express");
25
25
  express = __toESM(express);
26
+ let swagger_ui_express = require("swagger-ui-express");
27
+ swagger_ui_express = __toESM(swagger_ui_express);
26
28
  //#region src/html/404.ts
27
29
  /**
28
30
  * Default Express.js 404 error page, as a string.
@@ -256,15 +258,20 @@ var ParserError = class ParserError extends ResponseStatusError {
256
258
  case "reqbody": return "request body";
257
259
  case "reqparams": return "request params";
258
260
  case "reqquery": return "request query";
261
+ case "resbody": return "response body";
259
262
  }
260
263
  })()}: ${formatted}`;
261
264
  }
262
265
  };
263
266
  //#endregion
264
267
  //#region src/helper/sapling.ts
265
- const settings = {
268
+ const _settings = {
266
269
  serialize: JSON.stringify,
267
- deserialize: JSON.parse
270
+ deserialize: JSON.parse,
271
+ doc: {
272
+ openApiPath: "/openapi.json",
273
+ swaggerPath: "/swagger.html"
274
+ }
268
275
  };
269
276
  /**
270
277
  * Collection of utility functions which are essential for Sapling to function.
@@ -343,13 +350,13 @@ var Sapling = class Sapling {
343
350
  * @defaultValue `JSON.stringify`
344
351
  */
345
352
  static serialize(value) {
346
- return settings.serialize(value);
353
+ return _settings.serialize(value);
347
354
  }
348
355
  /**
349
356
  * Replace the function used for `serialize`.
350
357
  */
351
358
  static setSerializeFn(fn) {
352
- settings.serialize = fn;
359
+ _settings.serialize = fn;
353
360
  }
354
361
  /**
355
362
  * De-serialize a JSON string back to a JavaScript object.
@@ -361,16 +368,287 @@ var Sapling = class Sapling {
361
368
  * @defaultValue `JSON.parse`
362
369
  */
363
370
  static deserialize(value) {
364
- return settings.deserialize(value);
371
+ return _settings.deserialize(value);
365
372
  }
366
373
  /**
367
374
  * Replace the function used for `deserialize`
368
375
  */
369
376
  static setDeserializeFn(fn) {
370
- settings.deserialize = fn;
377
+ _settings.deserialize = fn;
378
+ }
379
+ static setOpenApiPath(path) {
380
+ _settings.doc.openApiPath = path;
381
+ }
382
+ static setSwaggerPath(path) {
383
+ _settings.doc.swaggerPath = path;
384
+ }
385
+ static chainHandlers(handlers, request, response, next, index = 0) {
386
+ if (index >= handlers.length) {
387
+ next();
388
+ return;
389
+ }
390
+ handlers[index]?.(request, response, (err) => {
391
+ if (err) {
392
+ next(err);
393
+ return;
394
+ }
395
+ Sapling.chainHandlers(handlers, request, response, next, index + 1);
396
+ });
371
397
  }
372
398
  };
373
399
  //#endregion
400
+ //#region src/annotation/route.ts
401
+ const _routeStore = /* @__PURE__ */ new WeakMap();
402
+ /**
403
+ * Custom annotation that will store all routes inside of a map,
404
+ * which can then be used to initialize all the routes to the router.
405
+ */
406
+ function _Route({ method, path = "" }) {
407
+ return (target, propertyKey) => {
408
+ const ctor = target.constructor;
409
+ const list = _routeStore.get(ctor) ?? [];
410
+ list.push({
411
+ method,
412
+ path: path ?? "",
413
+ fnName: String(propertyKey)
414
+ });
415
+ _routeStore.set(ctor, list);
416
+ };
417
+ }
418
+ /**
419
+ * Register GET route on the given path (default "") for the given controller.
420
+ */
421
+ const GET = (path = "") => _Route({
422
+ method: "GET",
423
+ path
424
+ });
425
+ /**
426
+ * Register POST route on the given path (default "") for the given controller.
427
+ */
428
+ const POST = (path = "") => _Route({
429
+ method: "POST",
430
+ path
431
+ });
432
+ /**
433
+ * Register PUT route on the given path (default "") for the given controller.
434
+ */
435
+ const PUT = (path = "") => _Route({
436
+ method: "PUT",
437
+ path
438
+ });
439
+ /**
440
+ * Register DELETE route on the given path (default "") for the given controller.
441
+ */
442
+ const DELETE = (path = "") => _Route({
443
+ method: "DELETE",
444
+ path
445
+ });
446
+ /**
447
+ * Register OPTIONS route on the given path (default "") for the given controller.
448
+ */
449
+ const OPTIONS = (path = "") => _Route({
450
+ method: "OPTIONS",
451
+ path
452
+ });
453
+ /**
454
+ * Register PATCH route on the given path (default "") for the given controller.
455
+ */
456
+ const PATCH = (path = "") => _Route({
457
+ method: "PATCH",
458
+ path
459
+ });
460
+ /**
461
+ * Register HEAD route on the given path (default "") for the given controller.
462
+ */
463
+ const HEAD = (path = "") => _Route({
464
+ method: "HEAD",
465
+ path
466
+ });
467
+ /**
468
+ * Register a middleware route on the given path (default "") for the given controller.
469
+ */
470
+ const Middleware = (path = "") => _Route({
471
+ method: "USE",
472
+ path
473
+ });
474
+ /**
475
+ * Given a class constructor, fetch all the routes attached.
476
+ */
477
+ function _getRoutes(ctor) {
478
+ return _routeStore.get(ctor) ?? [];
479
+ }
480
+ //#endregion
481
+ //#region src/utils.ts
482
+ function _getOrCreateMap(store, ctor) {
483
+ const existing = store.get(ctor);
484
+ if (existing) return existing;
485
+ const created = /* @__PURE__ */ new Map();
486
+ store.set(ctor, created);
487
+ return created;
488
+ }
489
+ //#endregion
490
+ //#region src/annotation/schema.ts
491
+ const _routeSchemaStore = /* @__PURE__ */ new WeakMap();
492
+ const _controllerSchemaStore = /* @__PURE__ */ new WeakMap();
493
+ function ControllerSchema(options) {
494
+ return (target) => {
495
+ _setControllerSchema(target, options);
496
+ };
497
+ }
498
+ function RouteSchema(options) {
499
+ return (target, propertyKey) => {
500
+ const ctor = target.constructor;
501
+ _setRouteSchema(ctor, String(propertyKey), options);
502
+ };
503
+ }
504
+ function _setRouteSchema(ctor, fnName, options) {
505
+ _getOrCreateMap(_routeSchemaStore, ctor).set(fnName, options);
506
+ }
507
+ function _setControllerSchema(ctor, options) {
508
+ _controllerSchemaStore.set(ctor, options);
509
+ }
510
+ function _getRouteSchema(ctor, fnName) {
511
+ return _routeSchemaStore.get(ctor)?.get(fnName);
512
+ }
513
+ function _getControllerSchema(ctor) {
514
+ return _controllerSchemaStore.get(ctor);
515
+ }
516
+ //#endregion
517
+ //#region src/helper/openapi.ts
518
+ var OpenAPIGenerator = class {
519
+ constructor() {
520
+ this.controllers = /* @__PURE__ */ new Set();
521
+ this.config = {
522
+ title: "API",
523
+ version: "1.0.0"
524
+ };
525
+ }
526
+ setConfig(config) {
527
+ this.config = config;
528
+ }
529
+ registerController(controllerClass, prefix) {
530
+ this.controllers.add({
531
+ class: controllerClass,
532
+ prefix
533
+ });
534
+ }
535
+ generateSpec() {
536
+ const config = this.config;
537
+ const paths = {};
538
+ const tags = [];
539
+ for (const { class: controllerClass, prefix } of this.controllers) {
540
+ const routes = _getRoutes(controllerClass);
541
+ const controllerSchema = _getControllerSchema(controllerClass);
542
+ if (controllerSchema?.title) tags.push({
543
+ name: controllerSchema.title,
544
+ description: controllerSchema.description
545
+ });
546
+ for (const route of routes) {
547
+ if (route.method === "USE") continue;
548
+ const schemas = _getValidatorSchema(controllerClass, route.fnName);
549
+ const routeSchema = _getRouteSchema(controllerClass, route.fnName);
550
+ if (route.path instanceof RegExp) throw new Error(`You have a route with a regex path of ${route.path.source}. This is not compatible with OpenAPI.`);
551
+ const openApiPath = (prefix + route.path).replace(/:([A-Za-z0-9_]+)/g, "{$1}");
552
+ if (!paths[openApiPath]) paths[openApiPath] = {};
553
+ const responses = {};
554
+ if (schemas?.responseBody) {
555
+ const responseSchema = this.toJsonSchema(schemas.responseBody, "output");
556
+ responses["200"] = {
557
+ description: responseSchema.description ?? "Successful response",
558
+ content: { "application/json": { schema: responseSchema } }
559
+ };
560
+ } else responses["200"] = { description: "Successful response" };
561
+ if (routeSchema?.responses) for (const resp of routeSchema.responses) {
562
+ const statusCode = String(resp.statusCode);
563
+ const existingResponse = responses[statusCode];
564
+ const existingSchema = existingResponse && "content" in existingResponse ? existingResponse.content?.["application/json"]?.schema : void 0;
565
+ const responseSchema = resp.schema ? this.toJsonSchema(resp.schema, "output") : statusCode === "200" ? existingSchema : void 0;
566
+ responses[statusCode] = {
567
+ ...existingResponse,
568
+ description: resp.description ?? responseSchema?.description ?? existingResponse?.description ?? `Response ${resp.statusCode}`,
569
+ ...responseSchema ? { content: { "application/json": { schema: responseSchema } } } : {}
570
+ };
571
+ }
572
+ const operation = {
573
+ responses,
574
+ summary: routeSchema?.summary,
575
+ description: routeSchema?.description,
576
+ tags: controllerSchema?.title ? [controllerSchema.title] : void 0
577
+ };
578
+ const parameters = [];
579
+ if (schemas?.requestParam) {
580
+ const paramSchema = this.toJsonSchema(schemas.requestParam, "input");
581
+ if (paramSchema.type === "object" && paramSchema.properties) for (const [name, schema] of Object.entries(paramSchema.properties)) {
582
+ const parameterSchema = schema;
583
+ parameters.push({
584
+ name,
585
+ in: "path",
586
+ required: true,
587
+ description: parameterSchema.description,
588
+ schema: parameterSchema
589
+ });
590
+ }
591
+ }
592
+ if (schemas?.requestQuery) {
593
+ const querySchema = this.toJsonSchema(schemas.requestQuery, "input");
594
+ if (querySchema.type === "object" && querySchema.properties) for (const [name, schema] of Object.entries(querySchema.properties)) {
595
+ const isRequired = Array.isArray(querySchema.required) && querySchema.required.includes(name);
596
+ const parameterSchema = schema;
597
+ parameters.push({
598
+ name,
599
+ in: "query",
600
+ required: isRequired,
601
+ description: parameterSchema.description,
602
+ schema: parameterSchema
603
+ });
604
+ }
605
+ }
606
+ if (parameters.length > 0) operation.parameters = parameters;
607
+ if (schemas?.requestBody) {
608
+ const requestSchema = this.toJsonSchema(schemas.requestBody, "input");
609
+ operation.requestBody = {
610
+ required: true,
611
+ description: requestSchema.description,
612
+ content: { "application/json": { schema: requestSchema } }
613
+ };
614
+ }
615
+ const method = route.method.toLowerCase();
616
+ paths[openApiPath][method] = operation;
617
+ }
618
+ }
619
+ return {
620
+ openapi: "3.0.0",
621
+ info: {
622
+ title: config.title,
623
+ version: config.version,
624
+ description: config.description
625
+ },
626
+ tags: tags.length > 0 ? tags : void 0,
627
+ paths
628
+ };
629
+ }
630
+ toJsonSchema(schema, direction = "output") {
631
+ try {
632
+ const jsonSchema = schema["~standard"].jsonSchema;
633
+ if (direction === "input" && jsonSchema.input) return jsonSchema.input({ target: "openapi-3.0" });
634
+ return jsonSchema.output({ target: "openapi-3.0" });
635
+ } catch (e) {
636
+ if (e instanceof Error && e.message.includes("Transforms cannot be represented in JSON Schema")) throw new Error(`${e.message}.\nIt appears that you are using z.transform() - it is highly recommended that you use z.codec instead - https://zod.dev/codecs`);
637
+ throw e;
638
+ }
639
+ }
640
+ };
641
+ const openApiGenerator = new OpenAPIGenerator();
642
+ function _registerControllerClass(controllerClass, prefix) {
643
+ openApiGenerator.registerController(controllerClass, prefix);
644
+ }
645
+ function setOpenApiConfig(config) {
646
+ openApiGenerator.setConfig(config);
647
+ }
648
+ function generateOpenApiSpec() {
649
+ return openApiGenerator.generateSpec();
650
+ }
651
+ //#endregion
374
652
  //#region src/types.ts
375
653
  const methodResolve = {
376
654
  GET: "get",
@@ -503,212 +781,58 @@ function _resolve(ctor) {
503
781
  return _InjectableRegistry.get(ctor);
504
782
  }
505
783
  //#endregion
506
- //#region src/annotation/request.ts
507
- const _requestSchemaStore = /* @__PURE__ */ new WeakMap();
508
- /**
509
- * Apply to a route method to have `request.body` be parsed by `schema`.
510
- *
511
- * This annotation will parse `request.body` & then override `request.body`.
512
- * You can then just simply cast `request.body` for your use
513
- *
514
- * @example
515
- * ```ts
516
- * const CREATE_BOOK_REQUEST_BODY_SCHEMA = z.object({
517
- * name: z.string(),
518
- * description: z.string().optional(),
519
- * });
520
- *
521
- * ⠀@Controller({ prefix: "/api/book" })
522
- * class BookController {
523
- * ⠀@RequestBody(CREATE_BOOK_REQUEST_BODY_SCHEMA)
524
- * ⠀@POST()
525
- * public createBook(request: e.Request) {
526
- * const { name, description } = request.body as unknown as z.infer<
527
- * typeof CREATE_BOOK_REQUEST_BODY_SCHEMA
528
- * >;
529
- * }
530
- * }
531
- * ```
532
- */
784
+ //#region src/annotation/validator.ts
785
+ const _validatorSchemaStore = /* @__PURE__ */ new WeakMap();
786
+ function ResponseBody(schema) {
787
+ return (target, propertyKey) => {
788
+ const ctor = target.constructor;
789
+ const fnName = String(propertyKey);
790
+ _setOnce(_getOrCreateSchemaDefinition(ctor, fnName), "responseBody", schema, fnName);
791
+ };
792
+ }
533
793
  function RequestBody(schema) {
534
794
  return (target, propertyKey) => {
535
795
  const ctor = target.constructor;
536
796
  const fnName = String(propertyKey);
537
- _setOnce(_getOrCreateRequestSchemaDefinition(ctor, fnName), "body", schema, fnName);
797
+ _setOnce(_getOrCreateSchemaDefinition(ctor, fnName), "requestBody", schema, fnName);
538
798
  };
539
799
  }
540
- /**
541
- * Apply to a route method to have `request.param` be parsed by `schema`.
542
- *
543
- * This annotation will parse `request.param` & then override `request.param`.
544
- * You can then just simply cast `request.param` for your use
545
- *
546
- * @example
547
- * ```ts
548
- * const GET_BOOK_REQUEST_PARAM_SCHEMA = z.object({
549
- * bookId: z.string(),
550
- * });
551
- *
552
- * ⠀@Controller({ prefix: "/api/book" })
553
- * class BookController {
554
- * ⠀@RequestParam(GET_BOOK_REQUEST_PARAM_SCHEMA)
555
- * ⠀@GET("/:bookId")
556
- * public getBook(request: e.Request) {
557
- * const { bookId } = request.param as unknown as z.infer<
558
- * typeof GET_BOOK_REQUEST_PARAM_SCHEMA
559
- * >;
560
- * }
561
- * }
562
- * ```
563
- */
564
800
  function RequestParam(schema) {
565
801
  return (target, propertyKey) => {
566
802
  const ctor = target.constructor;
567
803
  const fnName = String(propertyKey);
568
- _setOnce(_getOrCreateRequestSchemaDefinition(ctor, fnName), "param", schema, fnName);
804
+ _setOnce(_getOrCreateSchemaDefinition(ctor, fnName), "requestParam", schema, fnName);
569
805
  };
570
806
  }
571
- /**
572
- * Apply to a route method to have `request.query` be parsed by `schema`.
573
- *
574
- * This annotation will parse `request.query` & then override `request.query`.
575
- * You can then just simply cast `request.query` for your use
576
- *
577
- * @example
578
- * ```ts
579
- * const LIST_BOOKS_REQUEST_QUERY_SCHEMA = z.object({
580
- * sort: z.enum(["name", "createdAt"]).optional(),
581
- * q: z.string().optional(),
582
- * });
583
- *
584
- * ⠀@Controller({ prefix: "/api/book" })
585
- * class BookController {
586
- * ⠀@RequestQuery(LIST_BOOKS_REQUEST_QUERY_SCHEMA)
587
- * ⠀@GET()
588
- * public listBooks(request: e.Request) {
589
- * const { sort, q } = request.query as unknown as z.infer<
590
- * typeof LIST_BOOKS_REQUEST_QUERY_SCHEMA
591
- * >;
592
- * }
593
- * }
594
- * ```
595
- */
596
807
  function RequestQuery(schema) {
597
808
  return (target, propertyKey) => {
598
809
  const ctor = target.constructor;
599
810
  const fnName = String(propertyKey);
600
- _setOnce(_getOrCreateRequestSchemaDefinition(ctor, fnName), "query", schema, fnName);
811
+ _setOnce(_getOrCreateSchemaDefinition(ctor, fnName), "requestQuery", schema, fnName);
601
812
  };
602
813
  }
603
- function _getOrCreateRequestSchemaDefinition(ctor, fnName) {
604
- const byFn = (() => {
605
- const fn = _requestSchemaStore.get(ctor);
606
- if (fn) return fn;
607
- const newFn = /* @__PURE__ */ new Map();
608
- _requestSchemaStore.set(ctor, newFn);
609
- return newFn;
610
- })();
814
+ function _getOrCreateSchemaDefinition(ctor, fnName) {
815
+ const byFn = _getOrCreateMap(_validatorSchemaStore, ctor);
611
816
  const existing = byFn.get(fnName);
612
817
  if (existing) return existing;
613
818
  const created = {};
614
819
  byFn.set(fnName, created);
615
820
  return created;
616
821
  }
617
- function _setOnce(def, key, schema, fnName) {
618
- if (def[key]) throw new Error(`Duplicate request schema for "${String(key)}" on method "${fnName}"`);
619
- def[key] = schema;
620
- }
621
- function _getRequestSchemas(ctor, fnName) {
622
- return _requestSchemaStore.get(ctor)?.get(fnName);
623
- }
624
822
  async function _parseOrThrow(schema, input, kind) {
625
823
  const result = await schema["~standard"].validate(input);
626
824
  if (result.issues) {
627
- console.debug(`Failed to parse a schema`);
825
+ console.debug(`Failed to parse ${schema["~standard"].vendor} schema\nissues: ${result.issues}`);
628
826
  throw new ParserError(kind, result.issues, schema["~standard"].vendor);
629
827
  }
630
828
  return result.value;
631
829
  }
632
- //#endregion
633
- //#region src/annotation/route.ts
634
- const _routeStore = /* @__PURE__ */ new WeakMap();
635
- /**
636
- * Custom annotation that will store all routes inside of a map,
637
- * which can then be used to initialize all the routes to the router.
638
- */
639
- function _Route({ method, path = "" }) {
640
- return (target, propertyKey) => {
641
- const ctor = target.constructor;
642
- const list = _routeStore.get(ctor) ?? [];
643
- list.push({
644
- method,
645
- path: path ?? "",
646
- fnName: String(propertyKey)
647
- });
648
- _routeStore.set(ctor, list);
649
- };
830
+ function _getValidatorSchema(ctor, fnName) {
831
+ return _validatorSchemaStore.get(ctor)?.get(fnName);
650
832
  }
651
- /**
652
- * Register GET route on the given path (default "") for the given controller.
653
- */
654
- const GET = (path = "") => _Route({
655
- method: "GET",
656
- path
657
- });
658
- /**
659
- * Register POST route on the given path (default "") for the given controller.
660
- */
661
- const POST = (path = "") => _Route({
662
- method: "POST",
663
- path
664
- });
665
- /**
666
- * Register PUT route on the given path (default "") for the given controller.
667
- */
668
- const PUT = (path = "") => _Route({
669
- method: "PUT",
670
- path
671
- });
672
- /**
673
- * Register DELETE route on the given path (default "") for the given controller.
674
- */
675
- const DELETE = (path = "") => _Route({
676
- method: "DELETE",
677
- path
678
- });
679
- /**
680
- * Register OPTIONS route on the given path (default "") for the given controller.
681
- */
682
- const OPTIONS = (path = "") => _Route({
683
- method: "OPTIONS",
684
- path
685
- });
686
- /**
687
- * Register PATCH route on the given path (default "") for the given controller.
688
- */
689
- const PATCH = (path = "") => _Route({
690
- method: "PATCH",
691
- path
692
- });
693
- /**
694
- * Register HEAD route on the given path (default "") for the given controller.
695
- */
696
- const HEAD = (path = "") => _Route({
697
- method: "HEAD",
698
- path
699
- });
700
- /**
701
- * Register a middleware route on the given path (default "") for the given controller.
702
- */
703
- const Middleware = (path = "") => _Route({
704
- method: "USE",
705
- path
706
- });
707
- /**
708
- * Given a class constructor, fetch all the routes attached.
709
- */
710
- function _getRoutes(ctor) {
711
- return _routeStore.get(ctor) ?? [];
833
+ function _setOnce(def, key, schema, fnName) {
834
+ if (def[key]) throw new Error(`Duplicate schema for "${String(key)}" on method "${fnName}"`);
835
+ def[key] = schema;
712
836
  }
713
837
  //#endregion
714
838
  //#region src/annotation/controller.ts
@@ -722,6 +846,7 @@ const _ControllerRegistry = /* @__PURE__ */ new WeakMap();
722
846
  function Controller({ prefix = "", deps = [] } = {}) {
723
847
  return (target) => {
724
848
  const targetClass = target;
849
+ _registerControllerClass(target, prefix);
725
850
  const router = (0, express.Router)();
726
851
  const routes = _getRoutes(target);
727
852
  const usedRoutes = /* @__PURE__ */ new Set();
@@ -764,12 +889,12 @@ Split these into separate @MiddlewareClass classes, or merge the logic into a si
764
889
  return;
765
890
  }
766
891
  router[methodName](fp, async (request, response, next) => {
767
- const schemas = _getRequestSchemas(target, fnName);
892
+ const schemas = _getValidatorSchema(target, fnName);
768
893
  if (schemas) {
769
- if (schemas.body) request.body = await _parseOrThrow(schemas.body, request.body, "reqbody");
770
- if (schemas.param) request.params = await _parseOrThrow(schemas.param, request.params, "reqparams");
771
- if (schemas.query) {
772
- const parsedQuery = await _parseOrThrow(schemas.query, request.query, "reqquery");
894
+ if (schemas.requestBody) request.body = await _parseOrThrow(schemas.requestBody, request.body, "reqbody");
895
+ if (schemas.requestParam) request.params = await _parseOrThrow(schemas.requestParam, request.params, "reqparams");
896
+ if (schemas.requestQuery) {
897
+ const parsedQuery = await _parseOrThrow(schemas.requestQuery, request.query, "reqquery");
773
898
  Object.defineProperty(request, "query", {
774
899
  value: parsedQuery,
775
900
  writable: true,
@@ -779,7 +904,8 @@ Split these into separate @MiddlewareClass classes, or merge the logic into a si
779
904
  }
780
905
  const result = await fn.bind(controllerInstance)(request, response, next);
781
906
  if (result instanceof ResponseEntity) {
782
- response.contentType("application/json").status(result.getStatusCode()).set(result.getHeaders()).send(Sapling.serialize(result.getBody()));
907
+ const body = schemas && schemas.responseBody ? await _parseOrThrow(schemas.responseBody, result.getBody(), "resbody") : result.getBody();
908
+ response.contentType("application/json").status(result.getStatusCode()).set(result.getHeaders()).send(Sapling.serialize(body));
783
909
  return;
784
910
  }
785
911
  if (result instanceof RedirectView) {
@@ -813,7 +939,7 @@ function __decorate(decorators, target, key, desc) {
813
939
  return c > 3 && r && Object.defineProperty(target, key, r), r;
814
940
  }
815
941
  //#endregion
816
- //#region src/middleware/default/base.ts
942
+ //#region src/middleware/default/error/base.ts
817
943
  let DefaultBaseErrorMiddleware = class DefaultBaseErrorMiddleware {
818
944
  handle(err, _request, _response, _next) {
819
945
  console.error("[Error]", err);
@@ -823,7 +949,17 @@ let DefaultBaseErrorMiddleware = class DefaultBaseErrorMiddleware {
823
949
  __decorate([Middleware()], DefaultBaseErrorMiddleware.prototype, "handle", null);
824
950
  DefaultBaseErrorMiddleware = __decorate([MiddlewareClass()], DefaultBaseErrorMiddleware);
825
951
  //#endregion
826
- //#region src/middleware/default/responsestatus.ts
952
+ //#region src/middleware/default/error/parse.ts
953
+ let DefaultParserErrorMiddleware = class DefaultParserErrorMiddleware {
954
+ handle(err, _request, _response, next) {
955
+ if (err instanceof ParserError) return ResponseEntity.status(err.status).body({ message: err.message });
956
+ next(err);
957
+ }
958
+ };
959
+ __decorate([Middleware()], DefaultParserErrorMiddleware.prototype, "handle", null);
960
+ DefaultParserErrorMiddleware = __decorate([MiddlewareClass()], DefaultParserErrorMiddleware);
961
+ //#endregion
962
+ //#region src/middleware/default/error/responsestatus.ts
827
963
  let DefaultResponseStatusErrorMiddleware = class DefaultResponseStatusErrorMiddleware {
828
964
  handle(err, _request, _response, next) {
829
965
  if (err instanceof ResponseStatusError) return ResponseEntity.status(err.status).body({ message: err.message });
@@ -833,7 +969,43 @@ let DefaultResponseStatusErrorMiddleware = class DefaultResponseStatusErrorMiddl
833
969
  __decorate([Middleware()], DefaultResponseStatusErrorMiddleware.prototype, "handle", null);
834
970
  DefaultResponseStatusErrorMiddleware = __decorate([MiddlewareClass()], DefaultResponseStatusErrorMiddleware);
835
971
  //#endregion
972
+ //#region src/middleware/default/openapi/index.ts
973
+ let DefaultOpenApiMiddleware = class DefaultOpenApiMiddleware {
974
+ handle(_request, _response, _next) {
975
+ return ResponseEntity.ok().body(generateOpenApiSpec());
976
+ }
977
+ };
978
+ __decorate([GET(_settings.doc.openApiPath)], DefaultOpenApiMiddleware.prototype, "handle", null);
979
+ DefaultOpenApiMiddleware = __decorate([MiddlewareClass()], DefaultOpenApiMiddleware);
980
+ //#endregion
981
+ //#region src/middleware/default/swagger/index.ts
982
+ let Serve = class Serve {
983
+ constructor() {
984
+ this.handlers = swagger_ui_express.default.serve;
985
+ }
986
+ handle(request, response, next) {
987
+ return Sapling.chainHandlers(this.handlers, request, response, next);
988
+ }
989
+ };
990
+ __decorate([Middleware(_settings.doc.swaggerPath)], Serve.prototype, "handle", null);
991
+ Serve = __decorate([MiddlewareClass()], Serve);
992
+ let Setup = class Setup {
993
+ constructor() {
994
+ this.handler = swagger_ui_express.default.setup(null, { swaggerOptions: { url: _settings.doc.openApiPath } });
995
+ }
996
+ handle(request, response, next) {
997
+ return this.handler(request, response, next);
998
+ }
999
+ };
1000
+ __decorate([Middleware(_settings.doc.swaggerPath)], Setup.prototype, "handle", null);
1001
+ Setup = __decorate([MiddlewareClass()], Setup);
1002
+ const DefaultSwaggerMiddleware = {
1003
+ Serve,
1004
+ Setup
1005
+ };
1006
+ //#endregion
836
1007
  exports.Controller = Controller;
1008
+ exports.ControllerSchema = ControllerSchema;
837
1009
  exports.DELETE = DELETE;
838
1010
  Object.defineProperty(exports, "DefaultBaseErrorMiddleware", {
839
1011
  enumerable: true,
@@ -841,12 +1013,25 @@ Object.defineProperty(exports, "DefaultBaseErrorMiddleware", {
841
1013
  return DefaultBaseErrorMiddleware;
842
1014
  }
843
1015
  });
1016
+ Object.defineProperty(exports, "DefaultOpenApiMiddleware", {
1017
+ enumerable: true,
1018
+ get: function() {
1019
+ return DefaultOpenApiMiddleware;
1020
+ }
1021
+ });
1022
+ Object.defineProperty(exports, "DefaultParserErrorMiddleware", {
1023
+ enumerable: true,
1024
+ get: function() {
1025
+ return DefaultParserErrorMiddleware;
1026
+ }
1027
+ });
844
1028
  Object.defineProperty(exports, "DefaultResponseStatusErrorMiddleware", {
845
1029
  enumerable: true,
846
1030
  get: function() {
847
1031
  return DefaultResponseStatusErrorMiddleware;
848
1032
  }
849
1033
  });
1034
+ exports.DefaultSwaggerMiddleware = DefaultSwaggerMiddleware;
850
1035
  exports.GET = GET;
851
1036
  exports.HEAD = HEAD;
852
1037
  exports.Html404ErrorPage = Html404ErrorPage;
@@ -863,16 +1048,29 @@ exports.RedirectView = RedirectView;
863
1048
  exports.RequestBody = RequestBody;
864
1049
  exports.RequestParam = RequestParam;
865
1050
  exports.RequestQuery = RequestQuery;
1051
+ exports.ResponseBody = ResponseBody;
866
1052
  exports.ResponseEntity = ResponseEntity;
867
1053
  exports.ResponseEntityBuilder = ResponseEntityBuilder;
868
1054
  exports.ResponseStatusError = ResponseStatusError;
1055
+ exports.RouteSchema = RouteSchema;
869
1056
  exports.Sapling = Sapling;
870
1057
  exports._ControllerRegistry = _ControllerRegistry;
871
1058
  exports._InjectableDeps = _InjectableDeps;
872
1059
  exports._InjectableRegistry = _InjectableRegistry;
873
1060
  exports._Route = _Route;
874
- exports._getRequestSchemas = _getRequestSchemas;
1061
+ exports._getControllerSchema = _getControllerSchema;
1062
+ exports._getOrCreateSchemaDefinition = _getOrCreateSchemaDefinition;
1063
+ exports._getRouteSchema = _getRouteSchema;
875
1064
  exports._getRoutes = _getRoutes;
1065
+ exports._getValidatorSchema = _getValidatorSchema;
876
1066
  exports._parseOrThrow = _parseOrThrow;
1067
+ exports._registerControllerClass = _registerControllerClass;
877
1068
  exports._resolve = _resolve;
1069
+ exports._setControllerSchema = _setControllerSchema;
1070
+ exports._setOnce = _setOnce;
1071
+ exports._setRouteSchema = _setRouteSchema;
1072
+ exports._settings = _settings;
1073
+ exports.generateOpenApiSpec = generateOpenApiSpec;
878
1074
  exports.methodResolve = methodResolve;
1075
+ exports.openApiGenerator = openApiGenerator;
1076
+ exports.setOpenApiConfig = setOpenApiConfig;