@povio/openapi-codegen-cli 3.0.0-rc.14 → 3.0.0-rc.15

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/README.md CHANGED
@@ -215,6 +215,16 @@ import { ErrorHandler, OpenApiQueryConfig } from "@povio/openapi-codegen-cli";
215
215
  </OpenApiQueryConfig.Provider>;
216
216
  ```
217
217
 
218
+ ### Runtime response validation
219
+
220
+ Use `OpenApiQueryConfig.Provider` to allow generated GET query hooks to return invalid response data while still logging the response Zod error to the console. Non-GET requests still throw on invalid response data.
221
+
222
+ ```tsx
223
+ <OpenApiQueryConfig.Provider allowInvalidResponseData={import.meta.env.DEV}>
224
+ <App />
225
+ </OpenApiQueryConfig.Provider>
226
+ ```
227
+
218
228
  ### OpenApiWorkspaceContext (Path + ACL defaults)
219
229
 
220
230
  Set `workspaceContext` to a list of param names in codegen config (or pass `--workspaceContext officeId,projectId`) and wrap your app subtree with `OpenApiWorkspaceContext.Provider` if generated hooks frequently repeat workspace-scoped params.
@@ -277,6 +287,37 @@ export default defineConfig({
277
287
  The plugin runs on both `vite serve` and `vite build`, and watches local OpenAPI files in dev mode.
278
288
  If you provide `formatGeneratedFile`, the plugin formats each generated file in memory before comparing and writing it, which helps avoid unnecessary HMR when the formatted output is unchanged.
279
289
 
290
+ ### Metro Plugin
291
+
292
+ You can run codegen directly from React Native Metro config:
293
+
294
+ ```ts
295
+ import { fileURLToPath } from "url";
296
+ import { getDefaultConfig } from "@react-native/metro-config";
297
+ import { withOpenApiCodegen } from "@povio/openapi-codegen-cli/metro";
298
+
299
+ const root = fileURLToPath(new URL("./", import.meta.url));
300
+ const config = getDefaultConfig(root);
301
+
302
+ export default withOpenApiCodegen(
303
+ config,
304
+ {
305
+ input: "./openapi.yaml",
306
+ output: "./src/data",
307
+ inlineEndpoints: true,
308
+ incremental: true,
309
+ formatGeneratedFile: async ({ fileName, content }) => {
310
+ void fileName;
311
+ return content;
312
+ },
313
+ },
314
+ { root },
315
+ );
316
+ ```
317
+
318
+ The Metro wrapper runs generation when the config is loaded, waits for it before Metro transforms or serves the first request, and watches local OpenAPI files while the dev server is running.
319
+ If you provide `formatGeneratedFile`, it behaves the same way as the Vite plugin.
320
+
280
321
  ### Enums
281
322
 
282
323
  If you're using Enums in your backend DTOs with `@Expose()` and `@IsEnum`, they may still not appear correctly in the OpenAPI schema unless you also provide both `enum` **and** `enumName` to `@ApiProperty`.
package/dist/acl.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ErrorHandler } from "./error-handling-B4aYKmyL.mjs";
1
+ import { a as ErrorHandler } from "./error-handling-oM5YJYYH.mjs";
2
2
  import * as react from "react";
3
3
  import { PropsWithChildren } from "react";
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -1,4 +1,4 @@
1
- import { t as GenerateOptions } from "./options-BPAjzilp.mjs";
1
+ import { t as GenerateOptions } from "./options-BZOw7Hx4.mjs";
2
2
 
3
3
  //#region src/generators/types/config.d.ts
4
4
  type OpenAPICodegenConfig = Partial<GenerateOptions>;
@@ -1,4 +1,4 @@
1
- import { S as Profiler, h as deepMerge, i as writeGenerateFileData, p as DEFAULT_GENERATE_OPTIONS, r as removeStaleGeneratedFiles, t as generateCodeFromOpenAPIDoc } from "./generateCodeFromOpenAPIDoc-BtabB7FW.mjs";
1
+ import { S as Profiler, h as deepMerge, i as writeGenerateFileData, p as DEFAULT_GENERATE_OPTIONS, r as removeStaleGeneratedFiles, t as generateCodeFromOpenAPIDoc } from "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
2
2
  import path from "path";
3
3
  import SwaggerParser from "@apidevtools/swagger-parser";
4
4
 
@@ -3834,10 +3834,11 @@ function generateEndpoints({ resolver, data, tag }) {
3834
3834
  from: getAppRestClientImportPath(resolver.options)
3835
3835
  };
3836
3836
  const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
3837
- const hasAxiosImport = hasAxiosRequestConfig;
3837
+ const hasGetEndpoints = endpoints.some((endpoint) => endpoint.method === "get");
3838
+ const hasAxiosImport = hasAxiosRequestConfig || hasGetEndpoints;
3838
3839
  const axiosImport = {
3839
3840
  bindings: [],
3840
- typeBindings: hasAxiosRequestConfig ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
3841
+ typeBindings: hasAxiosImport ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
3841
3842
  from: AXIOS_IMPORT.from
3842
3843
  };
3843
3844
  const generateParse = resolver.options.parseRequestParams;
@@ -3875,9 +3876,10 @@ function generateEndpoints({ resolver, data, tag }) {
3875
3876
  const endpointBody = getEndpointBody$1(endpoint);
3876
3877
  const hasUndefinedEndpointBody = requiresBody(endpoint) && !endpointBody && hasEndpointConfig(endpoint, resolver);
3877
3878
  const endpointConfig = renderEndpointConfig(resolver, endpoint, tag);
3878
- lines.push(`export const ${getEndpointName(endpoint)} = (${endpointParams}${hasAxiosRequestConfig ? `${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
3879
+ const hasRequestConfigParam = hasAxiosRequestConfig || endpoint.method === "get";
3880
+ lines.push(`export const ${getEndpointName(endpoint)} = (${endpointParams}${hasRequestConfigParam ? `${AXIOS_REQUEST_CONFIG_NAME}?: ${getRequestConfigType$1()}` : ""}) => {`);
3879
3881
  lines.push(` return ${APP_REST_CLIENT_NAME}.${endpoint.method}(`);
3880
- lines.push(` { resSchema: ${getImportedZodSchemaName(resolver, endpoint.response, resolver.options.modelsInCommon && resolver.options.splitByTags ? tag : void 0)} },`);
3882
+ lines.push(` ${renderRequestInfo(resolver, endpoint, tag)},`);
3881
3883
  lines.push(` \`${getEndpointPath(endpoint)}\`,`);
3882
3884
  if (endpointBody) lines.push(` ${generateParse ? renderEndpointParamParse(resolver, endpointBody, endpointBody.name, tag) : endpointBody.name},`);
3883
3885
  else if (hasUndefinedEndpointBody) lines.push(" undefined,");
@@ -3888,6 +3890,12 @@ function generateEndpoints({ resolver, data, tag }) {
3888
3890
  if (resolver.options.tsNamespaces) lines.push("}");
3889
3891
  return lines.join("\n").trimEnd() + "\n";
3890
3892
  }
3893
+ function renderRequestInfo(resolver, endpoint, tag) {
3894
+ return `{ resSchema: ${getImportedZodSchemaName(resolver, endpoint.response, resolver.options.modelsInCommon && resolver.options.splitByTags ? tag : void 0)} }`;
3895
+ }
3896
+ function getRequestConfigType$1() {
3897
+ return `${AXIOS_REQUEST_CONFIG_TYPE} & { allowInvalidResponseData?: boolean }`;
3898
+ }
3891
3899
  function renderImport$2(importData) {
3892
3900
  const namedImports = [...importData.bindings, ...(importData.typeBindings ?? []).map((binding) => importData.typeOnly ? binding : `type ${binding}`)];
3893
3901
  const names = [...importData.defaultImport ? [importData.defaultImport] : [], ...namedImports.length > 0 ? [`{ ${namedImports.join(", ")} }`] : []].join(", ");
@@ -3913,12 +3921,12 @@ function getSortingPresenceChain$1(resolver, param) {
3913
3921
  }
3914
3922
  function renderEndpointConfig(resolver, endpoint, modelNamespaceTag) {
3915
3923
  const endpointConfig = getEndpointConfig(endpoint);
3916
- const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
3924
+ const hasRequestConfigParam = resolver.options.axiosRequestConfig || endpoint.method === "get";
3917
3925
  const needsBlobConfig = endpoint.mediaDownload || endpoint.response === "z.instanceof(Blob)";
3918
- if (Object.keys(endpointConfig).length === 0 && !needsBlobConfig) return hasAxiosRequestConfig ? AXIOS_REQUEST_CONFIG_NAME : "";
3926
+ if (Object.keys(endpointConfig).length === 0 && !needsBlobConfig) return hasRequestConfigParam ? AXIOS_REQUEST_CONFIG_NAME : "";
3919
3927
  const lines = [];
3920
3928
  lines.push("{");
3921
- if (hasAxiosRequestConfig) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
3929
+ if (hasRequestConfigParam) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
3922
3930
  if (endpointConfig.params) {
3923
3931
  lines.push(" params: {");
3924
3932
  for (const param of endpointConfig.params) {
@@ -4093,11 +4101,12 @@ function generateQueries(params) {
4093
4101
  const endpointGroups = groupEndpoints(endpoints, resolver);
4094
4102
  const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
4095
4103
  const hasAxiosDefaultImport = endpoints.some(({ mediaUpload }) => mediaUpload);
4096
- const hasAxiosImport = hasAxiosRequestConfig || hasAxiosDefaultImport;
4104
+ const hasGetEndpoints = endpoints.some((endpoint) => endpoint.method === "get");
4105
+ const hasAxiosImport = hasAxiosRequestConfig || hasAxiosDefaultImport || hasGetEndpoints;
4097
4106
  const axiosImport = {
4098
4107
  defaultImport: hasAxiosDefaultImport ? AXIOS_DEFAULT_IMPORT_NAME : void 0,
4099
4108
  bindings: [],
4100
- typeBindings: hasAxiosRequestConfig ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
4109
+ typeBindings: hasAxiosImport ? [AXIOS_REQUEST_CONFIG_TYPE] : [],
4101
4110
  from: AXIOS_IMPORT.from
4102
4111
  };
4103
4112
  const { queryEndpoints, infiniteQueryEndpoints, mutationEndpoints, aclEndpoints } = endpointGroups;
@@ -4128,7 +4137,7 @@ function generateQueries(params) {
4128
4137
  from: ACL_PACKAGE_IMPORT_PATH
4129
4138
  };
4130
4139
  const queryTypesImport = {
4131
- bindings: [...hasMutationDefaultOnError ? ["OpenApiQueryConfig"] : []],
4140
+ bindings: [...queryEndpoints.length > 0 || infiniteQueryEndpoints.length > 0 || hasMutationDefaultOnError ? ["OpenApiQueryConfig"] : []],
4132
4141
  typeBindings: [
4133
4142
  ...queryEndpoints.length > 0 ? [QUERY_OPTIONS_TYPES.query] : [],
4134
4143
  ...resolver.options.infiniteQueries && infiniteQueryEndpoints.length > 0 ? [QUERY_OPTIONS_TYPES.infiniteQuery] : [],
@@ -4431,9 +4440,10 @@ function renderInlineEndpoints({ resolver, endpoints, tag }) {
4431
4440
  const endpointBody = getEndpointBody$1(endpoint);
4432
4441
  const hasUndefinedEndpointBody = requiresBody(endpoint) && !endpointBody && hasEndpointConfig(endpoint, resolver);
4433
4442
  const endpointConfig = renderInlineEndpointConfig(resolver, endpoint, tag);
4434
- lines.push(`const ${getEndpointName(endpoint)} = (${endpointParams}${resolver.options.axiosRequestConfig ? `${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
4443
+ const hasRequestConfigParam = resolver.options.axiosRequestConfig || endpoint.method === "get";
4444
+ lines.push(`const ${getEndpointName(endpoint)} = (${endpointParams}${hasRequestConfigParam ? `${endpointParams ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}?: ${getRequestConfigType()}` : ""}) => {`);
4435
4445
  lines.push(` return ${APP_REST_CLIENT_NAME}.${endpoint.method}(`);
4436
- lines.push(` { resSchema: ${getImportedZodSchemaName(resolver, endpoint.response, tag)} },`);
4446
+ lines.push(` ${renderInlineRequestInfo(resolver, endpoint, tag)},`);
4437
4447
  lines.push(` \`${getEndpointPath(endpoint)}\`,`);
4438
4448
  if (endpointBody) lines.push(` ${resolver.options.parseRequestParams ? renderInlineEndpointParamParse(resolver, endpointBody, endpointBody.name, tag) : endpointBody.name},`);
4439
4449
  else if (hasUndefinedEndpointBody) lines.push(" undefined,");
@@ -4444,6 +4454,12 @@ function renderInlineEndpoints({ resolver, endpoints, tag }) {
4444
4454
  }
4445
4455
  return lines;
4446
4456
  }
4457
+ function renderInlineRequestInfo(resolver, endpoint, tag) {
4458
+ return `{ resSchema: ${getImportedZodSchemaName(resolver, endpoint.response, tag)} }`;
4459
+ }
4460
+ function getRequestConfigType() {
4461
+ return `${AXIOS_REQUEST_CONFIG_TYPE} & { allowInvalidResponseData?: boolean }`;
4462
+ }
4447
4463
  function renderInlineEndpointParamParse(resolver, param, paramName, modelNamespaceTag) {
4448
4464
  const addOptional = !(param.parameterObject ?? param.bodyObject)?.required && (Boolean(param.parameterSortingEnumSchemaName) || isNamedZodSchema(param.zodSchema));
4449
4465
  const schemaValue = param.parameterSortingEnumSchemaName ? `${ZOD_EXTENDED.namespace}.${ZOD_EXTENDED.exports.sortExp}(${getImportedZodSchemaName(resolver, param.parameterSortingEnumSchemaName, modelNamespaceTag)})${getSortingPresenceChain(resolver, param)}` : `${getImportedZodSchemaName(resolver, param.zodSchema, modelNamespaceTag)}${addOptional ? ".optional()" : ""}`;
@@ -4458,12 +4474,12 @@ function getSortingPresenceChain(resolver, param) {
4458
4474
  }
4459
4475
  function renderInlineEndpointConfig(resolver, endpoint, modelNamespaceTag) {
4460
4476
  const endpointConfig = getEndpointConfig(endpoint);
4461
- const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
4477
+ const hasRequestConfigParam = resolver.options.axiosRequestConfig || endpoint.method === "get";
4462
4478
  const needsBlobConfig = endpoint.mediaDownload || endpoint.response === "z.instanceof(Blob)";
4463
- if (Object.keys(endpointConfig).length === 0 && !needsBlobConfig) return hasAxiosRequestConfig ? AXIOS_REQUEST_CONFIG_NAME : "";
4479
+ if (Object.keys(endpointConfig).length === 0 && !needsBlobConfig) return hasRequestConfigParam ? AXIOS_REQUEST_CONFIG_NAME : "";
4464
4480
  const lines = [];
4465
4481
  lines.push("{");
4466
- if (hasAxiosRequestConfig) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
4482
+ if (hasRequestConfigParam) lines.push(` ...${AXIOS_REQUEST_CONFIG_NAME},`);
4467
4483
  if (endpointConfig.params) {
4468
4484
  lines.push(" params: {");
4469
4485
  for (const param of endpointConfig.params) {
@@ -4483,19 +4499,19 @@ function renderInlineEndpointConfig(resolver, endpoint, modelNamespaceTag) {
4483
4499
  return lines.join("\n");
4484
4500
  }
4485
4501
  function renderQueryOptions({ resolver, endpoint, inlineEndpoints }) {
4486
- const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
4502
+ const hasRequestConfigParam = resolver.options.axiosRequestConfig || endpoint.method === "get";
4487
4503
  const endpointParams = renderEndpointParams(resolver, endpoint, { modelNamespaceTag: getEndpointTag(endpoint, resolver.options) });
4488
4504
  const endpointArgs = renderEndpointArgs(resolver, endpoint, {});
4489
4505
  const endpointFunction = inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options);
4490
4506
  const lines = [];
4491
- lines.push(`const ${getQueryOptionsName(endpoint)} = (${endpointParams ? `{ ${endpointArgs} }: { ${endpointParams} }` : ""}${hasAxiosRequestConfig ? `${endpointParams ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => ({`);
4507
+ lines.push(`const ${getQueryOptionsName(endpoint)} = (${endpointParams ? `{ ${endpointArgs} }: { ${endpointParams} }` : ""}${hasRequestConfigParam ? `${endpointParams ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}?: ${getRequestConfigType()}` : ""}) => ({`);
4492
4508
  lines.push(` queryKey: keys.${getEndpointName(endpoint)}(${endpointArgs}),`);
4493
- lines.push(` queryFn: () => ${endpointFunction}(${endpointArgs}${hasAxiosRequestConfig ? `${endpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""}),`);
4509
+ lines.push(` queryFn: () => ${endpointFunction}(${endpointArgs}${hasRequestConfigParam ? `${endpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""}),`);
4494
4510
  lines.push("});");
4495
4511
  return lines.join("\n");
4496
4512
  }
4497
4513
  function renderInfiniteQueryOptions({ resolver, endpoint, inlineEndpoints }) {
4498
- const hasAxiosRequestConfig = resolver.options.axiosRequestConfig;
4514
+ const hasRequestConfigParam = resolver.options.axiosRequestConfig || endpoint.method === "get";
4499
4515
  const endpointParams = renderEndpointParams(resolver, endpoint, {
4500
4516
  excludePageParam: true,
4501
4517
  modelNamespaceTag: getEndpointTag(endpoint, resolver.options)
@@ -4504,9 +4520,9 @@ function renderInfiniteQueryOptions({ resolver, endpoint, inlineEndpoints }) {
4504
4520
  const endpointArgsWithPage = renderEndpointArgs(resolver, endpoint, { replacePageParam: true });
4505
4521
  const endpointFunction = inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options);
4506
4522
  const lines = [];
4507
- lines.push(`const ${getInfiniteQueryOptionsName(endpoint)} = (${endpointParams ? `{ ${endpointArgsWithoutPage} }: { ${endpointParams} }` : ""}${hasAxiosRequestConfig ? `${endpointParams ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => ({`);
4523
+ lines.push(`const ${getInfiniteQueryOptionsName(endpoint)} = (${endpointParams ? `{ ${endpointArgsWithoutPage} }: { ${endpointParams} }` : ""}${hasRequestConfigParam ? `${endpointParams ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}?: ${getRequestConfigType()}` : ""}) => ({`);
4508
4524
  lines.push(` queryKey: keys.${getEndpointName(endpoint)}Infinite(${endpointArgsWithoutPage}),`);
4509
- lines.push(` queryFn: ({ pageParam }: { pageParam: number }) => ${endpointFunction}(${endpointArgsWithPage}${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}` : ""}),`);
4525
+ lines.push(` queryFn: ({ pageParam }: { pageParam: number }) => ${endpointFunction}(${endpointArgsWithPage}${hasRequestConfigParam ? `, ${AXIOS_REQUEST_CONFIG_NAME}` : ""}),`);
4510
4526
  lines.push(" initialPageParam: 1,");
4511
4527
  lines.push(` getNextPageParam: ({ ${resolver.options.infiniteQueryResponseParamNames.page}, ${resolver.options.infiniteQueryResponseParamNames.totalItems}, ${resolver.options.infiniteQueryResponseParamNames.limit}: limitParam }: Awaited<ReturnType<typeof ${endpointFunction}>>) => {`);
4512
4528
  lines.push(` const pageParam = ${resolver.options.infiniteQueryResponseParamNames.page} ?? 1;`);
@@ -4553,7 +4569,8 @@ function renderQuery({ resolver, endpoint, inlineEndpoints }) {
4553
4569
  });
4554
4570
  const queryOptionsName = getQueryOptionsName(endpoint);
4555
4571
  const hasQueryFnOverride = hasAclCheck;
4556
- const queryOptionsArgs = `${resolvedEndpointArgs ? `{ ${resolvedEndpointArgs} }` : ""}${hasAxiosRequestConfig ? `${resolvedEndpointArgs ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""}`;
4572
+ const requestConfig = `{ ${hasAxiosRequestConfig ? `...${AXIOS_REQUEST_CONFIG_NAME}, ` : ""}allowInvalidResponseData: queryConfig.allowInvalidResponseData }`;
4573
+ const queryOptionsArgs = `${resolvedEndpointArgs ? `{ ${resolvedEndpointArgs} }, ` : ""}${requestConfig}`;
4557
4574
  const lines = [];
4558
4575
  lines.push(renderQueryJsDocs({
4559
4576
  resolver,
@@ -4562,6 +4579,7 @@ function renderQuery({ resolver, endpoint, inlineEndpoints }) {
4562
4579
  tag
4563
4580
  }));
4564
4581
  lines.push(`export const ${getQueryName(endpoint)} = <TData>(${endpointParams ? `{ ${endpointArgs} }: { ${endpointParams} }, ` : ""}options?: AppQueryOptions<typeof ${inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options)}, TData>${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
4582
+ lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();");
4565
4583
  if (hasAclCheck) lines.push(` const { checkAcl } = ${ACL_CHECK_HOOK}();`);
4566
4584
  lines.push(...renderWorkspaceParamResolutions({
4567
4585
  replacements: workspaceParamReplacements,
@@ -4761,7 +4779,8 @@ function renderInfiniteQuery({ resolver, endpoint, inlineEndpoints }) {
4761
4779
  const endpointArgsWithoutPage = renderEndpointArgs(resolver, endpoint, { excludePageParam: true });
4762
4780
  const resolvedEndpointArgsWithoutPage = renderEndpointObjectArgs(resolver, endpoint, { excludePageParam: true }, workspaceParamReplacements);
4763
4781
  const queryOptionsName = getInfiniteQueryOptionsName(endpoint);
4764
- const queryOptionsArgs = `${resolvedEndpointArgsWithoutPage ? `{ ${resolvedEndpointArgsWithoutPage} }` : ""}${hasAxiosRequestConfig ? `${resolvedEndpointArgsWithoutPage ? ", " : ""}${AXIOS_REQUEST_CONFIG_NAME}` : ""}`;
4782
+ const requestConfig = `{ ${hasAxiosRequestConfig ? `...${AXIOS_REQUEST_CONFIG_NAME}, ` : ""}allowInvalidResponseData: queryConfig.allowInvalidResponseData }`;
4783
+ const queryOptionsArgs = `${resolvedEndpointArgsWithoutPage ? `{ ${resolvedEndpointArgsWithoutPage} }, ` : ""}${requestConfig}`;
4765
4784
  const hasQueryFnOverride = hasAclCheck;
4766
4785
  const lines = [];
4767
4786
  lines.push(renderQueryJsDocs({
@@ -4771,6 +4790,7 @@ function renderInfiniteQuery({ resolver, endpoint, inlineEndpoints }) {
4771
4790
  tag
4772
4791
  }));
4773
4792
  lines.push(`export const ${getInfiniteQueryName(endpoint)} = <TData>(${endpointParams ? `{ ${endpointArgsWithoutPage} }: { ${endpointParams} }, ` : ""}options?: AppInfiniteQueryOptions<typeof ${inlineEndpoints ? getEndpointName(endpoint) : getImportedEndpointName(endpoint, resolver.options)}, TData>${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`);
4793
+ lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();");
4774
4794
  if (hasAclCheck) lines.push(` const { checkAcl } = ${ACL_CHECK_HOOK}();`);
4775
4795
  lines.push(...renderWorkspaceParamResolutions({
4776
4796
  replacements: workspaceParamReplacements,
@@ -1,4 +1,4 @@
1
- import { n as GenerateFileData, t as GenerateOptions } from "./options-BPAjzilp.mjs";
1
+ import { n as GenerateFileData, t as GenerateOptions } from "./options-BZOw7Hx4.mjs";
2
2
  import { OpenAPIV3 } from "openapi-types";
3
3
 
4
4
  //#region src/generators/types/metadata.d.ts
@@ -1,4 +1,4 @@
1
- import { _ as getNamespaceName, a as getDataFromOpenAPIDoc, b as isParamMediaTypeAllowed, c as getSchemaTsMetaType, d as getTagImportPath, f as getQueryName, g as invalidVariableNameCharactersToCamel, l as getTsTypeBase, o as isMutation, p as DEFAULT_GENERATE_OPTIONS, s as isQuery, t as generateCodeFromOpenAPIDoc, v as GenerateType, x as formatTag, y as isMediaTypeAllowed } from "./generateCodeFromOpenAPIDoc-BtabB7FW.mjs";
1
+ import { _ as getNamespaceName, a as getDataFromOpenAPIDoc, b as isParamMediaTypeAllowed, c as getSchemaTsMetaType, d as getTagImportPath, f as getQueryName, g as invalidVariableNameCharactersToCamel, l as getTsTypeBase, o as isMutation, p as DEFAULT_GENERATE_OPTIONS, s as isQuery, t as generateCodeFromOpenAPIDoc, v as GenerateType, x as formatTag, y as isMediaTypeAllowed } from "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
2
2
  import SwaggerParser from "@apidevtools/swagger-parser";
3
3
 
4
4
  //#region src/generators/core/getMetadataFromOpenAPIDoc.ts
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as ErrorHandler, c as SharedErrorHandler, i as ErrorEntry, n as DomainErrorEntry, o as ErrorHandlerOptions, r as DomainErrorRegistry, s as GeneralErrorCodes, t as ApplicationException } from "./error-handling-B4aYKmyL.mjs";
2
- import "./options-BPAjzilp.mjs";
3
- import { t as OpenAPICodegenConfig } from "./config-C1ME3Ay4.mjs";
1
+ import { a as ErrorHandler, c as SharedErrorHandler, i as ErrorEntry, n as DomainErrorEntry, o as ErrorHandlerOptions, r as DomainErrorRegistry, s as GeneralErrorCodes, t as ApplicationException } from "./error-handling-oM5YJYYH.mjs";
2
+ import "./options-BZOw7Hx4.mjs";
3
+ import { t as OpenAPICodegenConfig } from "./config-CrZa_Jbm.mjs";
4
4
  import { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosResponseHeaders, CreateAxiosDefaults } from "axios";
5
5
  import { z } from "zod";
6
6
  import "i18next";
@@ -26,6 +26,7 @@ interface RequestInfo<ZOutput, ECodes extends string> {
26
26
  }
27
27
  interface RequestConfig<IsRawRes extends boolean = false> {
28
28
  rawResponse?: IsRawRes;
29
+ allowInvalidResponseData?: boolean;
29
30
  }
30
31
  type Response<ZOutput, IsRawRes extends boolean = false> = IsRawRes extends true ? AxiosResponse<ZOutput> : ZOutput;
31
32
  interface RestClient {
@@ -90,6 +91,7 @@ declare namespace OpenApiQueryConfig {
90
91
  invalidateCurrentModule?: boolean;
91
92
  invalidationMap?: InvalidationMap<TQueryModule>;
92
93
  crossTabInvalidation?: boolean;
94
+ allowInvalidResponseData?: boolean;
93
95
  onError?: (error: unknown) => void;
94
96
  }
95
97
  type ProviderProps<TQueryModule extends QueryModule = QueryModule> = Type<TQueryModule>;
@@ -98,6 +100,7 @@ declare namespace OpenApiQueryConfig {
98
100
  invalidateCurrentModule,
99
101
  invalidationMap,
100
102
  crossTabInvalidation,
103
+ allowInvalidResponseData,
101
104
  onError,
102
105
  children
103
106
  }: PropsWithChildren<ProviderProps<TQueryModule>>): react_jsx_runtime0.JSX.Element;
package/dist/index.mjs CHANGED
@@ -66,10 +66,18 @@ var RestClient = class {
66
66
  async makeRequest(requestInfo, requestConfig) {
67
67
  const errorStack = (/* @__PURE__ */ new Error()).stack;
68
68
  try {
69
- const { rawResponse, ...config } = requestConfig;
69
+ const { rawResponse, allowInvalidResponseData, ...config } = requestConfig;
70
70
  const res = await this.client(config);
71
71
  const responseData = res.status === 204 && res.data === "" ? void 0 : res.data;
72
- const resData = requestInfo.resSchema.parse(responseData);
72
+ const parseResult = requestInfo.resSchema.safeParse(responseData);
73
+ let resData;
74
+ if (parseResult.success) resData = parseResult.data;
75
+ else if (allowInvalidResponseData && config.method === "get") {
76
+ parseResult.error.name = "BE Response schema mismatch - ZodError";
77
+ parseResult.error.stack = [parseResult.error.stack, ...errorStack?.split("\n").slice(2) ?? []].join("\n");
78
+ console.error(parseResult.error);
79
+ resData = res.data;
80
+ } else throw parseResult.error;
73
81
  return rawResponse ? {
74
82
  ...res,
75
83
  data: resData
@@ -114,18 +122,20 @@ var RestInterceptor = class {
114
122
  let OpenApiQueryConfig;
115
123
  (function(_OpenApiQueryConfig) {
116
124
  const Context = createContext({});
117
- function Provider({ preferUpdate, invalidateCurrentModule, invalidationMap, crossTabInvalidation, onError, children }) {
125
+ function Provider({ preferUpdate, invalidateCurrentModule, invalidationMap, crossTabInvalidation, allowInvalidResponseData, onError, children }) {
118
126
  const value = useMemo(() => ({
119
127
  preferUpdate,
120
128
  invalidateCurrentModule,
121
129
  invalidationMap,
122
130
  crossTabInvalidation,
131
+ allowInvalidResponseData,
123
132
  onError
124
133
  }), [
125
134
  preferUpdate,
126
135
  invalidateCurrentModule,
127
136
  invalidationMap,
128
137
  crossTabInvalidation,
138
+ allowInvalidResponseData,
129
139
  onError
130
140
  ]);
131
141
  return /* @__PURE__ */ jsx(Context.Provider, {
@@ -0,0 +1,32 @@
1
+ import { r as GenerateFileFormatter } from "./options-BZOw7Hx4.mjs";
2
+ import { t as OpenAPICodegenConfig } from "./config-CrZa_Jbm.mjs";
3
+ import { IncomingMessage, ServerResponse } from "http";
4
+
5
+ //#region src/metro/openapi-codegen.plugin.d.ts
6
+ type OpenApiCodegenMetroConfig = OpenAPICodegenConfig & {
7
+ formatGeneratedFile?: GenerateFileFormatter;
8
+ };
9
+ type OpenApiCodegenMetroOptions = {
10
+ root?: string;
11
+ watchOpenApiInput?: boolean;
12
+ };
13
+ type MetroNextFunction = (error?: unknown) => void;
14
+ type MetroMiddleware = (request: IncomingMessage, response: ServerResponse, next: MetroNextFunction) => unknown;
15
+ type MetroServer = unknown;
16
+ type MetroConfig = {
17
+ projectRoot?: string;
18
+ server?: {
19
+ enhanceMiddleware?: (middleware: MetroMiddleware, server: MetroServer) => MetroMiddleware;
20
+ [key: string]: unknown;
21
+ };
22
+ transformer?: {
23
+ getTransformOptions?: (...args: unknown[]) => unknown;
24
+ [key: string]: unknown;
25
+ };
26
+ watchFolders?: readonly string[];
27
+ [key: string]: unknown;
28
+ };
29
+ declare function withOpenApiCodegen<TMetroConfig extends MetroConfig>(metroConfig: Promise<TMetroConfig>, codegenConfig: OpenApiCodegenMetroConfig, options?: OpenApiCodegenMetroOptions): Promise<TMetroConfig>;
30
+ declare function withOpenApiCodegen<TMetroConfig extends MetroConfig>(metroConfig: TMetroConfig, codegenConfig: OpenApiCodegenMetroConfig, options?: OpenApiCodegenMetroOptions): TMetroConfig;
31
+ //#endregion
32
+ export { type MetroConfig, type MetroMiddleware, type OpenAPICodegenConfig, type OpenApiCodegenMetroConfig, type OpenApiCodegenMetroOptions, withOpenApiCodegen };
package/dist/metro.mjs ADDED
@@ -0,0 +1,86 @@
1
+ import "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
2
+ import "./generate.runner-DmjWJwgS.mjs";
3
+ import { t as createOpenApiCodegenRunner } from "./openapi-codegen.runner-CtfeBizk.mjs";
4
+ import fs from "fs";
5
+ import path from "path";
6
+
7
+ //#region src/metro/openapi-codegen.plugin.ts
8
+ function withOpenApiCodegen(metroConfig, codegenConfig, options = {}) {
9
+ if (isPromiseLike(metroConfig)) return metroConfig.then((resolvedConfig) => withResolvedOpenApiCodegen(resolvedConfig, codegenConfig, options));
10
+ return withResolvedOpenApiCodegen(metroConfig, codegenConfig, options);
11
+ }
12
+ function withResolvedOpenApiCodegen(metroConfig, codegenConfig, options) {
13
+ const root = path.resolve(options.root ?? metroConfig.projectRoot ?? process.cwd());
14
+ const codegen = createOpenApiCodegenRunner(codegenConfig);
15
+ const originalEnhanceMiddleware = metroConfig.server?.enhanceMiddleware;
16
+ const originalGetTransformOptions = metroConfig.transformer?.getTransformOptions;
17
+ let startupSucceeded = false;
18
+ let inflightGenerate;
19
+ let inputWatcher;
20
+ const requestStartupGenerate = () => {
21
+ if (startupSucceeded) return Promise.resolve();
22
+ if (inflightGenerate) return inflightGenerate;
23
+ const attempt = codegen.enqueueGenerate(root).then(() => {
24
+ startupSucceeded = true;
25
+ inflightGenerate = void 0;
26
+ }, (error) => {
27
+ inflightGenerate = void 0;
28
+ throw error;
29
+ });
30
+ inflightGenerate = attempt;
31
+ return attempt;
32
+ };
33
+ const ensureInputWatcher = () => {
34
+ if (options.watchOpenApiInput === false || inputWatcher) return;
35
+ const inputPath = codegen.getLocalInputPath(root);
36
+ if (!inputPath) return;
37
+ try {
38
+ inputWatcher = fs.watch(inputPath, { persistent: false }, () => {
39
+ startupSucceeded = false;
40
+ requestStartupGenerate().catch(reportGenerateError);
41
+ });
42
+ inputWatcher.on("error", reportWatcherError);
43
+ } catch (error) {
44
+ reportWatcherError(error);
45
+ }
46
+ };
47
+ const wrappedConfig = {
48
+ ...metroConfig,
49
+ server: {
50
+ ...metroConfig.server,
51
+ enhanceMiddleware(middleware, server) {
52
+ ensureInputWatcher();
53
+ const enhancedMiddleware = originalEnhanceMiddleware ? originalEnhanceMiddleware(middleware, server) : middleware;
54
+ return async (request, response, next) => {
55
+ try {
56
+ await requestStartupGenerate();
57
+ return await enhancedMiddleware(request, response, next);
58
+ } catch (error) {
59
+ next(error);
60
+ }
61
+ };
62
+ }
63
+ },
64
+ transformer: {
65
+ ...metroConfig.transformer,
66
+ async getTransformOptions(...args) {
67
+ await requestStartupGenerate();
68
+ return originalGetTransformOptions ? originalGetTransformOptions(...args) : void 0;
69
+ }
70
+ }
71
+ };
72
+ if (options.root || metroConfig.projectRoot) wrappedConfig.projectRoot = root;
73
+ return wrappedConfig;
74
+ }
75
+ function isPromiseLike(value) {
76
+ return typeof value.then === "function";
77
+ }
78
+ function reportGenerateError(error) {
79
+ console.error("[openapi-codegen] Failed to generate OpenAPI client from Metro config.", error);
80
+ }
81
+ function reportWatcherError(error) {
82
+ console.error("[openapi-codegen] Failed to watch OpenAPI input from Metro config.", error);
83
+ }
84
+
85
+ //#endregion
86
+ export { withOpenApiCodegen };
@@ -0,0 +1,42 @@
1
+ import { S as Profiler } from "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
2
+ import { t as runGenerate } from "./generate.runner-DmjWJwgS.mjs";
3
+ import path from "path";
4
+
5
+ //#region src/plugins/openapi-codegen.runner.ts
6
+ function createOpenApiCodegenRunner(config) {
7
+ let queue = Promise.resolve();
8
+ const { formatGeneratedFile, ...fileConfig } = config;
9
+ const enqueueGenerate = (root) => {
10
+ const run = queue.catch(() => void 0).then(async () => {
11
+ const profiler = new Profiler(process.env.OPENAPI_CODEGEN_PROFILE === "1");
12
+ await runGenerate({
13
+ fileConfig: normalizeOpenApiCodegenPaths(fileConfig, root),
14
+ formatGeneratedFile,
15
+ profiler
16
+ });
17
+ });
18
+ queue = run.then(() => void 0, () => void 0);
19
+ return run;
20
+ };
21
+ return {
22
+ enqueueGenerate,
23
+ getLocalInputPath: (root) => getLocalInputPath(config.input, root),
24
+ isLocalInput: isLocalOpenApiInput(config.input)
25
+ };
26
+ }
27
+ function normalizeOpenApiCodegenPaths(config, root) {
28
+ const normalized = { ...config };
29
+ if (typeof normalized.output === "string" && !path.isAbsolute(normalized.output)) normalized.output = path.resolve(root, normalized.output);
30
+ if (typeof normalized.input === "string" && !path.isAbsolute(normalized.input) && isLocalOpenApiInput(normalized.input)) normalized.input = path.resolve(root, normalized.input);
31
+ return normalized;
32
+ }
33
+ function getLocalInputPath(input, root) {
34
+ if (!isLocalOpenApiInput(input)) return;
35
+ return path.resolve(root, input);
36
+ }
37
+ function isLocalOpenApiInput(input) {
38
+ return typeof input === "string" && !/^https?:\/\//i.test(input);
39
+ }
40
+
41
+ //#endregion
42
+ export { createOpenApiCodegenRunner as t };
package/dist/sh.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { C as VALIDATION_ERROR_TYPE_TITLE, S as Profiler, a as getDataFromOpenAPIDoc, m as groupByType, n as getOutputFileName, u as getTagFileName, v as GenerateType } from "./generateCodeFromOpenAPIDoc-BtabB7FW.mjs";
3
- import { n as resolveConfig, t as runGenerate } from "./generate.runner-FyKVhmec.mjs";
2
+ import { C as VALIDATION_ERROR_TYPE_TITLE, S as Profiler, a as getDataFromOpenAPIDoc, m as groupByType, n as getOutputFileName, u as getTagFileName, v as GenerateType } from "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
3
+ import { n as resolveConfig, t as runGenerate } from "./generate.runner-DmjWJwgS.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import yargs from "yargs";
6
6
  import { hideBin } from "yargs/helpers";
@@ -39,7 +39,7 @@ function logBanner(message) {
39
39
  * Fetch the version from package.json
40
40
  */
41
41
  function getVersion() {
42
- return "3.0.0-rc.14";
42
+ return "3.0.0-rc.15";
43
43
  }
44
44
 
45
45
  //#endregion
package/dist/vite.d.mts CHANGED
@@ -1,11 +1,14 @@
1
- import { r as GenerateFileFormatter } from "./options-BPAjzilp.mjs";
2
- import { t as OpenAPICodegenConfig } from "./config-C1ME3Ay4.mjs";
1
+ import { r as GenerateFileFormatter } from "./options-BZOw7Hx4.mjs";
2
+ import { t as OpenAPICodegenConfig } from "./config-CrZa_Jbm.mjs";
3
3
  import { Plugin } from "vite";
4
4
 
5
- //#region src/vite/openapi-codegen.plugin.d.ts
6
- type OpenApiCodegenViteConfig = OpenAPICodegenConfig & {
5
+ //#region src/plugins/openapi-codegen.runner.d.ts
6
+ type OpenApiCodegenPluginConfig = OpenAPICodegenConfig & {
7
7
  formatGeneratedFile?: GenerateFileFormatter;
8
8
  };
9
+ //#endregion
10
+ //#region src/vite/openapi-codegen.plugin.d.ts
11
+ type OpenApiCodegenViteConfig = OpenApiCodegenPluginConfig;
9
12
  declare function openApiCodegen(config: OpenApiCodegenViteConfig): Plugin;
10
13
  //#endregion
11
14
  export { type OpenAPICodegenConfig, type OpenApiCodegenViteConfig, openApiCodegen };
package/dist/vite.mjs CHANGED
@@ -1,28 +1,20 @@
1
- import { S as Profiler } from "./generateCodeFromOpenAPIDoc-BtabB7FW.mjs";
2
- import { t as runGenerate } from "./generate.runner-FyKVhmec.mjs";
1
+ import "./generateCodeFromOpenAPIDoc-DjVJepG8.mjs";
2
+ import "./generate.runner-DmjWJwgS.mjs";
3
+ import { t as createOpenApiCodegenRunner } from "./openapi-codegen.runner-CtfeBizk.mjs";
3
4
  import path from "path";
4
5
 
5
6
  //#region src/vite/openapi-codegen.plugin.ts
6
7
  function openApiCodegen(config) {
7
8
  let resolvedViteConfig;
8
- let queue = Promise.resolve();
9
- const isLocalInput = typeof config.input === "string" && !/^https?:\/\//i.test(config.input);
10
- const { formatGeneratedFile, ...normalizedConfig } = config;
9
+ const codegen = createOpenApiCodegenRunner(config);
11
10
  const enqueueGenerate = () => {
12
- queue = queue.then(async () => {
13
- const currentConfig = resolvedViteConfig;
14
- if (!currentConfig) return;
15
- await runGenerate({
16
- fileConfig: normalizePaths(normalizedConfig, currentConfig.root),
17
- formatGeneratedFile,
18
- profiler: new Profiler(process.env.OPENAPI_CODEGEN_PROFILE === "1")
19
- });
20
- });
21
- return queue;
11
+ const currentConfig = resolvedViteConfig;
12
+ if (!currentConfig) return Promise.resolve();
13
+ return codegen.enqueueGenerate(currentConfig.root);
22
14
  };
23
15
  const setupWatcher = (server) => {
24
- if (!isLocalInput || !config.input) return;
25
- const openApiPath = path.resolve(server.config.root, config.input);
16
+ const openApiPath = codegen.getLocalInputPath(server.config.root);
17
+ if (!openApiPath) return;
26
18
  server.watcher.add(openApiPath);
27
19
  server.watcher.on("change", (changedPath) => {
28
20
  if (path.resolve(changedPath) === openApiPath) enqueueGenerate();
@@ -42,12 +34,6 @@ function openApiCodegen(config) {
42
34
  }
43
35
  };
44
36
  }
45
- function normalizePaths(config, root) {
46
- const normalized = { ...config };
47
- if (typeof normalized.output === "string" && !path.isAbsolute(normalized.output)) normalized.output = path.resolve(root, normalized.output);
48
- if (typeof normalized.input === "string" && !path.isAbsolute(normalized.input) && !/^https?:\/\//i.test(normalized.input)) normalized.input = path.resolve(root, normalized.input);
49
- return normalized;
50
- }
51
37
 
52
38
  //#endregion
53
39
  export { openApiCodegen };
package/dist/zod.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ErrorHandler } from "./error-handling-B4aYKmyL.mjs";
1
+ import { a as ErrorHandler } from "./error-handling-oM5YJYYH.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/zod.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@povio/openapi-codegen-cli",
3
- "version": "3.0.0-rc.14",
3
+ "version": "3.0.0-rc.15",
4
4
  "keywords": [
5
5
  "codegen",
6
6
  "openapi",
@@ -35,6 +35,10 @@
35
35
  "types": "./dist/vite.d.mts",
36
36
  "import": "./dist/vite.mjs"
37
37
  },
38
+ "./metro": {
39
+ "types": "./dist/metro.d.mts",
40
+ "import": "./dist/metro.mjs"
41
+ },
38
42
  "./generator": {
39
43
  "types": "./dist/generator.d.mts",
40
44
  "import": "./dist/generator.mjs"