@lucaapp/service-utils 5.24.2 → 5.24.4

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.
@@ -75,6 +75,7 @@ class Api {
75
75
  description: this.apiDescription,
76
76
  },
77
77
  });
78
+ (0, openapi_1.forcePathParamsRequired)(spec);
78
79
  return spec;
79
80
  }
80
81
  mountSwaggerMiddlewares() {
@@ -1,5 +1,11 @@
1
1
  import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
2
2
  import { EndpointOptions } from './types/endpoint';
3
3
  type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
4
+ export declare const forcePathParamsRequired: (spec: {
5
+ paths?: Record<string, unknown>;
6
+ components?: {
7
+ parameters?: Record<string, unknown>;
8
+ };
9
+ }) => void;
4
10
  export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean) => void;
5
11
  export {};
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerEndpoint = void 0;
3
+ exports.registerEndpoint = exports.forcePathParamsRequired = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const http_1 = require("./types/http");
6
6
  const mapExpressParamsToOpenAPIParams = (path) => path.replaceAll(/\:([^\:\/]+)/g, '{$1}');
7
7
  const buildResponseConfig = (responseOptions) => {
8
8
  const responses = {};
9
9
  responseOptions.forEach(response => {
10
+ // raw responses end the request outside the schema layer and carry the
11
+ // placeholder status 0, which is not a valid OpenAPI response key
12
+ if (response.isRawResponseEnd) {
13
+ return;
14
+ }
10
15
  const isAlreadyPresent = !!responses[String(response.status)];
11
16
  if (!isAlreadyPresent) {
12
17
  responses[String(response.status)] = {
@@ -36,8 +41,46 @@ const buildResponseConfig = (responseOptions) => {
36
41
  existingResponse.content['application/json'].schema =
37
42
  existingResponse.content['application/json'].schema.or(response.schema);
38
43
  });
44
+ const hasRawResponse = responseOptions.some(response => response.isRawResponseEnd);
45
+ if (hasRawResponse && !responses['200']) {
46
+ responses['200'] = { description: 'OK (raw response)' };
47
+ }
39
48
  return responses;
40
49
  };
50
+ // OpenAPI requires path parameters to be required, but zod effects (e.g.
51
+ // z.preprocess) hide the underlying optionality from the generator
52
+ const forcePathParamsRequired = (spec) => {
53
+ const markRequired = (parameters) => {
54
+ if (!Array.isArray(parameters)) {
55
+ return;
56
+ }
57
+ parameters.forEach(parameter => {
58
+ if (parameter?.in === 'path') {
59
+ parameter.required = true;
60
+ }
61
+ });
62
+ };
63
+ Object.values(spec.paths || {}).forEach(pathItem => {
64
+ if (!pathItem || typeof pathItem !== 'object') {
65
+ return;
66
+ }
67
+ Object.entries(pathItem).forEach(([key, value]) => {
68
+ if (key === 'parameters') {
69
+ markRequired(value);
70
+ return;
71
+ }
72
+ if (value && typeof value === 'object') {
73
+ markRequired(value.parameters);
74
+ }
75
+ });
76
+ });
77
+ Object.values(spec.components?.parameters || {}).forEach(parameter => {
78
+ if (parameter?.in === 'path') {
79
+ parameter.required = true;
80
+ }
81
+ });
82
+ };
83
+ exports.forcePathParamsRequired = forcePathParamsRequired;
41
84
  const registerEndpoint = (registry, method, prefixPath, path, summary,
42
85
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
86
  options, tags, debug) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "5.24.2",
3
+ "version": "5.24.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [