@povio/openapi-codegen-cli 3.2.0-rc.8 → 3.3.0-rc.1

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.
Files changed (44) hide show
  1. package/README.md +2 -51
  2. package/dist/acl.d.mts +19 -6
  3. package/dist/acl.mjs +7 -6
  4. package/dist/{auth.context-YFWzkwoN.mjs → auth.context-BAz8frX9.mjs} +1 -2
  5. package/dist/{config-DgrOddSC.d.mts → config-BQqze8rU.d.mts} +2 -1
  6. package/dist/{error-handling-BMXC5P08.mjs → error-handling-CsnufAil.mjs} +12 -22
  7. package/dist/{error-handling-CNOHs4Fc.d.mts → error-handling-D6ZYITQ3.d.mts} +4 -1
  8. package/dist/generate.runner-BeCGJ1ar.mjs +87 -0
  9. package/dist/{generateCodeFromOpenAPIDoc-CZT3sThI.cjs → generateCodeFromOpenAPIDoc-KQT4kYxY.mjs} +2375 -1403
  10. package/dist/generator.d.mts +10 -3
  11. package/dist/generator.mjs +4 -6
  12. package/dist/index.d.mts +47 -12
  13. package/dist/index.mjs +3 -6
  14. package/dist/metro.cjs +4861 -112
  15. package/dist/metro.d.mts +4 -3
  16. package/dist/metro.mjs +3 -3
  17. package/dist/{openapi-codegen.runner-C93V7SGj.mjs → openapi-codegen.runner-nPBssrBL.mjs} +2 -2
  18. package/dist/{openapi-source.runner-BZ6ZLgRO.mjs → openapi-source.runner-8kCe-g9S.mjs} +6 -18
  19. package/dist/{openapi-source.runner-ykstqlPC.d.mts → openapi-source.runner-B6KKrXw7.d.mts} +8 -2
  20. package/dist/{options-KPf-Fti5.d.mts → options-DdQJ9BSc.d.mts} +1 -6
  21. package/dist/sh.d.mts +1 -1
  22. package/dist/sh.mjs +53 -36
  23. package/dist/tiny.d.mts +1 -1
  24. package/dist/tiny.mjs +1 -1
  25. package/dist/vite.d.mts +4 -3
  26. package/dist/vite.mjs +4 -5
  27. package/dist/zod.d.mts +7 -2
  28. package/dist/zod.mjs +1 -1
  29. package/package.json +22 -32
  30. package/dist/generate.runner-BvSprH6D.mjs +0 -1683
  31. package/dist/generate.utils-CH2U2Dpr.cjs +0 -2314
  32. package/dist/generateCodeFromOpenAPIDoc-glAKBEGP.mjs +0 -2036
  33. package/dist/getDataFromOpenAPIDoc-7RxjULpB.mjs +0 -2011
  34. package/dist/native-rest-interceptor-CAWR8H5Y.mjs +0 -208
  35. package/dist/native-rest-interceptor-Cz6saoq5.d.mts +0 -46
  36. package/dist/native.d.mts +0 -3
  37. package/dist/native.mjs +0 -3
  38. package/dist/openapi-codegen-native-darwin-arm64.node +0 -0
  39. package/dist/openapi-codegen-native-linux-x64.node +0 -0
  40. package/dist/openapi-codegen-native-win32-x64.node +0 -0
  41. package/dist/rest-transport.types-DM5-qyOJ.d.mts +0 -66
  42. package/dist/rest-transport.types-DxitRtsB.mjs +0 -11
  43. package/dist/rest.d.mts +0 -2
  44. package/dist/rest.mjs +0 -2
package/README.md CHANGED
@@ -89,8 +89,7 @@ bunx openapi-codegen generate --config my-config.ts
89
89
  --modelsInCommon Keep all schema declarations in defaultTag models and emit per-module proxy exports (default: false)
90
90
  --replaceOptionalWithNullish Replace `.optional()` chains with `.nullish()` in generated Zod schemas (default: false)
91
91
 
92
- --restClient REST transport to generate: 'axios' or 'native' (default: 'axios')
93
- --axiosRequestConfig Include transport request config parameters in query hooks (default: false)
92
+ --axiosRequestConfig Include Axios request config parameters in query hooks (default: false)
94
93
  --infiniteQueries Generate infinite queries for paginated API endpoints (default: false)
95
94
  --mutationEffects Add mutation effects options to mutation hooks (default: true)
96
95
  --mutationScope Serialize mutations for the same path-param resource via TanStack scope.id (default: false).
@@ -139,7 +138,7 @@ bun install
139
138
  # run tests
140
139
  bun run test
141
140
 
142
- # run TypeScript sources directly with Bun
141
+ # run sources with tsx
143
142
  bun run start --help
144
143
  bun run start generate --input ./test/petstore.yaml --verbose
145
144
 
@@ -151,58 +150,10 @@ bun run start --help
151
150
  bun run start:dist generate --input ./test/petstore.yaml --verbose
152
151
  ```
153
152
 
154
- ### Native Bun code generation
155
-
156
- The Bun and Node.js CLIs and the Vite plugin automatically use the bundled Rust code-generation core when a compatible native binary is available. Generated files remain byte-for-byte compatible with the TypeScript implementation, which is retained as the fallback when the addon cannot be loaded.
157
-
158
- Set `OPENAPI_CODEGEN_NATIVE=0` to force the TypeScript path, or `OPENAPI_CODEGEN_NATIVE=1` to require the native path and fail when its binary is unavailable.
159
-
160
- Release packages include native binaries for Linux x64, macOS arm64, and Windows x64. Build a binary for the current platform with `bun run build:native`.
161
-
162
153
  ## Common Issues
163
154
 
164
155
  ### App REST Client Interceptors
165
156
 
166
- Select the fetch-based client without changing endpoint and query APIs:
167
-
168
- ```ts
169
- import type { OpenAPICodegenConfig } from "@povio/openapi-codegen-cli";
170
-
171
- export default {
172
- restClient: "native",
173
- } satisfies OpenAPICodegenConfig;
174
- ```
175
-
176
- Native mode imports common request/response contracts from `@povio/openapi-codegen-cli/rest` and the concrete
177
- `NativeRestClient` from `@povio/openapi-codegen-cli/native`. It uses `fetch` for normal requests and uploads, switching
178
- to `XMLHttpRequest` in browsers only when an upload progress callback is provided.
179
-
180
- Native interceptors use the common transport interface:
181
-
182
- ```ts
183
- import { NativeRestClient } from "@povio/openapi-codegen-cli/native";
184
- import type { RestTransportInterceptor } from "@povio/openapi-codegen-cli/rest";
185
-
186
- const authorizationInterceptor: RestTransportInterceptor = {
187
- onRequest(request) {
188
- request.headers.set("Authorization", `Bearer ${localStorage.getItem("accessToken")}`);
189
- return request;
190
- },
191
- };
192
-
193
- export const AppRestClient = new NativeRestClient({
194
- config: { baseURL: "https://api.example.com" },
195
- interceptors: [authorizationInterceptor],
196
- });
197
- ```
198
-
199
- Axios remains the default for backward compatibility. The existing Axios interceptor API remains available in Axios
200
- mode.
201
-
202
- Native mode does not run the library `ErrorHandler` or create `ApplicationException` values. It throws `HttpError` for
203
- non-success HTTP responses and preserves Zod, network, cancellation, and timeout errors so applications can handle them
204
- directly in query callbacks, error boundaries, or their own normalization layer.
205
-
206
157
  In order to add interceptors to the used REST client, you must create your own instance of a RestClient and pass your implemented interceptors into the constructor. Make sure to set `restClientImportPath` in your openapi generation configuration too.
207
158
 
208
159
  ```ts
package/dist/acl.d.mts CHANGED
@@ -1,21 +1,25 @@
1
- import { a as ErrorHandler } from "./error-handling-CNOHs4Fc.mjs";
1
+ import { a as ErrorHandler } from "./error-handling-D6ZYITQ3.mjs";
2
+ import * as _$react from "react";
2
3
  import { PropsWithChildren } from "react";
3
4
  import { AbilityTuple, PureAbility, RawRuleOf, Subject } from "@casl/ability";
4
5
  import { PackRule } from "@casl/ability/extra";
5
6
  import { BoundCanProps } from "@casl/react";
7
+
6
8
  //#region src/lib/acl/appAbility.types.d.ts
7
9
  type AppAbilities = AbilityTuple<string, Subject>;
8
10
  type AppAbility = PureAbility<AppAbilities>;
9
11
  //#endregion
10
12
  //#region src/lib/acl/ability.context.d.ts
11
13
  declare namespace AbilityContext {
12
- export const Consumer: import("react").Consumer<AppAbility>;
14
+ export const Consumer: _$react.Consumer<AppAbility>;
13
15
  interface ProviderProps {
14
16
  user?: {
15
17
  aclRules?: PackRule<RawRuleOf<AppAbility>>[];
16
18
  } | null;
17
19
  }
18
- export const Provider: ({ children }: PropsWithChildren<ProviderProps>) => import("react").JSX.Element;
20
+ export const Provider: ({
21
+ children
22
+ }: PropsWithChildren<ProviderProps>) => _$react.JSX.Element;
19
23
  export const useAbility: <TAppAbilities extends AppAbilities = AppAbilities>() => PureAbility<TAppAbilities>;
20
24
  export {};
21
25
  }
@@ -25,20 +29,29 @@ interface AclGuardProps<TAppAbilities extends AppAbilities = AppAbilities> {
25
29
  canUse: TAppAbilities;
26
30
  redirectTo?: string;
27
31
  }
28
- declare const createAclGuard: <TAppAbilities extends AppAbilities = AppAbilities>() => ({ canUse, redirectTo, children }: PropsWithChildren<AclGuardProps<TAppAbilities>>) => import("react").ReactNode;
32
+ declare const createAclGuard: <TAppAbilities extends AppAbilities = AppAbilities>() => ({
33
+ canUse,
34
+ redirectTo,
35
+ children
36
+ }: PropsWithChildren<AclGuardProps<TAppAbilities>>) => _$react.ReactNode;
29
37
  //#endregion
30
38
  //#region src/lib/acl/Can.d.ts
31
39
  type CanAbility = PureAbility<AbilityTuple<AppAbilities[0], AppAbilities[1]>>;
32
40
  type CanProps<TAppAbilities extends AppAbilities = AppAbilities> = {
33
41
  use: TAppAbilities;
34
42
  } & Omit<BoundCanProps<CanAbility>, "do" | "I" | "on" | "a" | "an" | "this">;
35
- declare const Can: <TAppAbilities extends AppAbilities = AppAbilities>({ use, ...props }: CanProps<TAppAbilities>) => import("react").JSX.Element;
43
+ declare const Can: <TAppAbilities extends AppAbilities = AppAbilities>({
44
+ use,
45
+ ...props
46
+ }: CanProps<TAppAbilities>) => _$react.JSX.Element;
36
47
  //#endregion
37
48
  //#region src/lib/acl/useAclCheck.d.ts
38
49
  interface UseAclCheckProps {
39
50
  errorHandler?: ErrorHandler<never>;
40
51
  }
41
- declare function useAclCheck<TAppAbilities extends AppAbilities = AppAbilities>({ errorHandler }?: UseAclCheckProps): {
52
+ declare function useAclCheck<TAppAbilities extends AppAbilities = AppAbilities>({
53
+ errorHandler
54
+ }?: UseAclCheckProps): {
42
55
  checkAcl: (appAbility: TAppAbilities) => void;
43
56
  };
44
57
  //#endregion
package/dist/acl.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { i as SharedErrorHandler } from "./error-handling-BMXC5P08.mjs";
2
- import { n as OpenApiRouter, t as AuthContext } from "./auth.context-YFWzkwoN.mjs";
3
- import { createContext, useCallback, useMemo } from "react";
1
+ import { i as SharedErrorHandler } from "./error-handling-CsnufAil.mjs";
2
+ import { n as OpenApiRouter, t as AuthContext } from "./auth.context-BAz8frX9.mjs";
3
+ import { createContext, useCallback, useEffect, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { AbilityBuilder, createMongoAbility } from "@casl/ability";
6
6
  import { unpackRules } from "@casl/ability/extra";
@@ -14,15 +14,16 @@ let AbilityContext;
14
14
  const { Consumer } = Context;
15
15
  _AbilityContext.Consumer = Consumer;
16
16
  _AbilityContext.Provider = ({ children }) => {
17
+ const [ability, setAbility] = useState(initialAppAbility);
17
18
  const { user } = AuthContext.useAuth();
18
- const ability = useMemo(() => {
19
- if (!user || !("aclRules" in user)) return initialAppAbility;
19
+ useEffect(() => {
20
+ if (!user || !("aclRules" in user)) return;
20
21
  const { can, build } = createAppAbilityBuilder();
21
22
  const packedRules = user.aclRules;
22
23
  unpackRules(packedRules).forEach(({ action, subject, conditions }) => {
23
24
  can(action, subject, conditions);
24
25
  });
25
- return build();
26
+ setAbility(build());
26
27
  }, [user]);
27
28
  return /* @__PURE__ */ jsx(Context.Provider, {
28
29
  value: ability,
@@ -5,9 +5,8 @@ let OpenApiRouter;
5
5
  (function(_OpenApiRouter) {
6
6
  const Context = createContext(null);
7
7
  _OpenApiRouter.Provider = ({ children, replace }) => {
8
- const value = useMemo(() => ({ replace }), [replace]);
9
8
  return /* @__PURE__ */ jsx(Context, {
10
- value,
9
+ value: useMemo(() => ({ replace }), [replace]),
11
10
  children
12
11
  });
13
12
  };
@@ -1,4 +1,5 @@
1
- import { t as GenerateOptions } from "./options-KPf-Fti5.mjs";
1
+ import { t as GenerateOptions } from "./options-DdQJ9BSc.mjs";
2
+
2
3
  //#region src/generators/types/config.d.ts
3
4
  type OpenAPICodegenConfig = Partial<GenerateOptions>;
4
5
  //#endregion
@@ -1,4 +1,4 @@
1
- import { t as HttpError } from "./rest-transport.types-DxitRtsB.mjs";
1
+ import { isAxiosError, isCancel } from "axios";
2
2
  import { z } from "zod";
3
3
  //#region src/lib/assets/locales/en/translation.json
4
4
  var translation_default$1 = { openapi: { "sharedErrors": {
@@ -35,26 +35,14 @@ function resolveT() {
35
35
  return getT();
36
36
  }
37
37
  //#endregion
38
- //#region src/lib/rest/http-error.utils.ts
39
- function isAxiosErrorLike(error) {
40
- return typeof error === "object" && error !== null && "isAxiosError" in error;
41
- }
42
- function isCanceledRequest(error) {
43
- if (error instanceof DOMException && ["AbortError", "TimeoutError"].includes(error.name)) return true;
44
- if (isAxiosErrorLike(error)) return error.code === "ERR_CANCELED" || error.code === "ECONNABORTED";
45
- return false;
46
- }
47
- //#endregion
48
38
  //#region src/lib/rest/rest.utils.ts
49
- function getResponseData(error) {
50
- if (error instanceof HttpError) return error.response.data;
51
- return isAxiosErrorLike(error) ? error.response?.data : void 0;
52
- }
53
39
  let RestUtils;
54
40
  (function(_RestUtils) {
55
41
  _RestUtils.extractServerResponseCode = (e) => {
56
42
  if (e instanceof z.ZodError) return "validation-exception";
57
- const data = getResponseData(e);
43
+ if (!isAxiosError(e)) return null;
44
+ if (!e.response) return null;
45
+ const data = e.response.data;
58
46
  if (typeof data?.code === "string") return data.code;
59
47
  if (typeof data?.code === "number") return data.code;
60
48
  return null;
@@ -66,7 +54,9 @@ let RestUtils;
66
54
  };
67
55
  const extractServerErrorMessage = _RestUtils.extractServerErrorMessage = (e) => {
68
56
  if (e instanceof z.ZodError) return e.message;
69
- const data = getResponseData(e);
57
+ if (!isAxiosError(e)) return null;
58
+ if (!e.response) return null;
59
+ const data = e.response.data;
70
60
  if (typeof data?.message === "string") return data.message;
71
61
  return null;
72
62
  };
@@ -119,8 +109,7 @@ var ErrorHandler = class ErrorHandler {
119
109
  const internalError = {
120
110
  code: "INTERNAL_ERROR",
121
111
  condition: (e) => {
122
- if (isAxiosErrorLike(e)) return e.response?.status != null && e.response.status >= 500 && e.response.status < 600;
123
- if (e instanceof HttpError) return e.response.status >= 500 && e.response.status < 600;
112
+ if (isAxiosError(e)) return e.response?.status != null && e.response.status >= 500 && e.response.status < 600;
124
113
  return false;
125
114
  },
126
115
  getMessage: () => resolveT()("openapi.sharedErrors.internalError", { ns })
@@ -128,8 +117,7 @@ var ErrorHandler = class ErrorHandler {
128
117
  const networkError = {
129
118
  code: "NETWORK_ERROR",
130
119
  condition: (e) => {
131
- if (isAxiosErrorLike(e)) return e.code === "ERR_NETWORK";
132
- if (e instanceof TypeError) return true;
120
+ if (isAxiosError(e)) return e.code === "ERR_NETWORK";
133
121
  return false;
134
122
  },
135
123
  getMessage: () => resolveT()("openapi.sharedErrors.networkError", { ns })
@@ -137,7 +125,9 @@ var ErrorHandler = class ErrorHandler {
137
125
  const canceledError = {
138
126
  code: "CANCELED_ERROR",
139
127
  condition: (e) => {
140
- return isCanceledRequest(e);
128
+ if (isCancel(e)) return true;
129
+ if (isAxiosError(e) && e.code === "ECONNABORTED") return true;
130
+ return false;
141
131
  },
142
132
  getMessage: () => resolveT()("openapi.sharedErrors.canceledError", { ns })
143
133
  };
@@ -69,7 +69,10 @@ declare class ErrorHandler<CodeT extends string | number> {
69
69
  private readonly userEntries;
70
70
  private readonly generalEntries;
71
71
  private onRethrowError?;
72
- constructor({ entries, onRethrowError }: ErrorHandlerOptions<CodeT>);
72
+ constructor({
73
+ entries,
74
+ onRethrowError
75
+ }: ErrorHandlerOptions<CodeT>);
73
76
  private matchesEntry;
74
77
  /** Lazy so resolveT() only runs when getMessage actually uses `t`. */
75
78
  private static lazyT;
@@ -0,0 +1,87 @@
1
+ import { h as deepMerge, i as writeGenerateFileData, p as DEFAULT_GENERATE_OPTIONS, r as removeStaleGeneratedFiles, t as generateCodeFromOpenAPIDoc, x as Profiler } from "./generateCodeFromOpenAPIDoc-KQT4kYxY.mjs";
2
+ import path from "path";
3
+ import SwaggerParser from "@apidevtools/swagger-parser";
4
+ //#region src/generators/core/resolveConfig.ts
5
+ function resolveConfig({ fileConfig = {}, params: { includeTags, excludeTags, inlineEndpointsExcludeModules, workspaceContext, ...options } }) {
6
+ const resolvedConfig = deepMerge(DEFAULT_GENERATE_OPTIONS, fileConfig ?? {}, {
7
+ ...options,
8
+ includeTags: includeTags?.split(","),
9
+ excludeTags: excludeTags?.split(","),
10
+ inlineEndpointsExcludeModules: inlineEndpointsExcludeModules?.split(","),
11
+ workspaceContext: workspaceContext?.split(",")
12
+ });
13
+ resolvedConfig.checkAcl = resolvedConfig.acl && resolvedConfig.checkAcl;
14
+ resolvedConfig.workspaceContext = Array.from(new Set((resolvedConfig.workspaceContext ?? []).map((value) => value.trim()).filter(Boolean)));
15
+ return resolvedConfig;
16
+ }
17
+ //#endregion
18
+ //#region src/generators/run/generate.runner.ts
19
+ async function runGenerate({ fileConfig, params, formatGeneratedFile, profiler = new Profiler(process.env.OPENAPI_CODEGEN_PROFILE === "1") }) {
20
+ const config = profiler.runSync("config.resolve", () => resolveConfig({
21
+ fileConfig,
22
+ params: params ?? {}
23
+ }));
24
+ const openApiDoc = await getOpenApiDoc(config.input, profiler);
25
+ const filesData = profiler.runSync("generate.total", () => generateCodeFromOpenAPIDoc(openApiDoc, config, profiler));
26
+ if (config.clearOutput) profiler.runSync("files.removeStaleGenerated", () => {
27
+ removeStaleGeneratedFiles({
28
+ output: config.output,
29
+ filesData,
30
+ options: config
31
+ });
32
+ });
33
+ await profiler.runAsync("files.write", async () => {
34
+ await writeGenerateFileData(filesData, { formatGeneratedFile });
35
+ });
36
+ return {
37
+ skipped: false,
38
+ config,
39
+ stats: getGenerateStats(filesData, config)
40
+ };
41
+ }
42
+ async function getOpenApiDoc(input, profiler) {
43
+ const parsedDoc = await profiler.runAsync("openapi.parse", async () => await SwaggerParser.parse(input));
44
+ if (!profiler.runSync("openapi.detectExternalRefs", () => hasExternalRef(parsedDoc))) return parsedDoc;
45
+ return await profiler.runAsync("openapi.bundle", async () => await SwaggerParser.bundle(input));
46
+ }
47
+ function hasExternalRef(value) {
48
+ const stack = [value];
49
+ const visited = /* @__PURE__ */ new Set();
50
+ while (stack.length > 0) {
51
+ const current = stack.pop();
52
+ if (!current || typeof current !== "object") continue;
53
+ if (visited.has(current)) continue;
54
+ visited.add(current);
55
+ if ("$ref" in current && typeof current.$ref === "string" && !current.$ref.startsWith("#/")) return true;
56
+ for (const nested of Object.values(current)) if (nested && typeof nested === "object") stack.push(nested);
57
+ }
58
+ return false;
59
+ }
60
+ function getGenerateStats(filesData, config) {
61
+ const generatedFilesCount = filesData.length;
62
+ if (generatedFilesCount === 0) return {
63
+ generatedFilesCount,
64
+ generatedModulesCount: 0
65
+ };
66
+ if (!config.splitByTags) return {
67
+ generatedFilesCount,
68
+ generatedModulesCount: 1
69
+ };
70
+ const moduleSuffixes = new Set(Object.values(config.configs).map((generateConfig) => generateConfig.outputFileNameSuffix).filter(Boolean));
71
+ const modules = /* @__PURE__ */ new Set();
72
+ for (const file of filesData) {
73
+ const segments = path.relative(config.output, file.fileName).split(path.sep).filter(Boolean);
74
+ if (segments.length < 2) continue;
75
+ const moduleName = segments[0];
76
+ const fileName = segments[segments.length - 1];
77
+ if (!fileName.startsWith(`${moduleName}.`)) continue;
78
+ const suffix = fileName.slice(moduleName.length + 1).replace(/\.tsx?$/, "");
79
+ if (moduleSuffixes.has(suffix)) modules.add(moduleName);
80
+ }
81
+ return {
82
+ generatedFilesCount,
83
+ generatedModulesCount: modules.size
84
+ };
85
+ }
86
+ //#endregion
87
+ export { resolveConfig as n, runGenerate as t };