Skip to content

Conversation

@carvalhocaio
Copy link
Contributor

@carvalhocaio carvalhocaio commented Oct 24, 2025

chore: update @hey-api/openapi-ts to the latest version #74

Description

Current State

  • Current version: @hey-api/openapi-ts@^0.60.1
  • Target version: 0.83.1 (latest as of 2025-10-24)
  • Version jump: 23 minor versions (significant upgrade with breaking changes)
  • Node.js version: v24.8.0 ✅ (meets requirement for Node 20.19+)

Breaking Changes Impact Assessment

Critical Changes (0.60 → 0.83):

  1. v0.73.0+: Clients are now bundled by default - may affect @hey-api/client-axios dependency
  2. v0.78.0: Configuration restructuring - options moved to new parser group
  3. v0.85.0: Output options now use null instead of false for disabled options
  4. v0.75.0: Plugin API changes (.subscribe() replaced with .forEach())

Motivation and Context

Screenshots (if appropriate):

Steps to reproduce (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires documentation updates.
  • I have updated the documentation accordingly.
  • My change requires dependencies updates.
  • I have updated the dependencies accordingly.

fix: update import path for OpenAPI client in clientConfig.ts

chore: modify openapi-ts configuration to include client-axios plugin

chore: bump package versions in package.json and pnpm-lock.yaml

fix: update watcher script to use pnpm for generating client on file change
@sourcery-ai
Copy link

sourcery-ai bot commented Oct 24, 2025

Reviewer's Guide

This PR upgrades the OpenAPI client generation to @hey-api/[email protected] (including Axios support and SSE streams), adjusts linting to ignore the generated directory, updates package dependencies and scripts, and regenerates all client types, SDK functions, and core utilities to match the new codegen API.

Class diagram for regenerated OpenAPI client types and SDK

classDiagram
  class Client {
    +buildUrl(options)
    +connect(options)
    +delete(options)
    +get(options)
    +getConfig()
    +head(options)
    +instance: AxiosInstance
    +options(options)
    +patch(options)
    +post(options)
    +put(options)
    +request(options)
    +setConfig(config)
    +sse: SseMethods
    +trace(options)
  }
  class SseMethods {
    +connect(options)
    +delete(options)
    +get(options)
    +head(options)
    +options(options)
    +patch(options)
    +post(options)
    +put(options)
    +trace(options)
  }
  class Config {
    +auth
    +bodySerializer
    +headers
    +method
    +querySerializer
    +requestValidator
    +responseTransformer
    +responseValidator
    +axios
    +baseURL
    +throwOnError
  }
  class RequestOptions {
    +body
    +path
    +query
    +security
    +url
    +headers
    +onSseError
    +onSseEvent
    +sseDefaultRetryDelay
    +sseMaxRetryAttempts
    +sseMaxRetryDelay
  }
  class ServerSentEventsOptions {
    +fetch
    +onRequest
    +onSseError
    +onSseEvent
    +serializedBody
    +sseDefaultRetryDelay
    +sseMaxRetryAttempts
    +sseMaxRetryDelay
    +sseSleepFn
    +url
  }
  class ServerSentEventsResult {
    +stream: AsyncGenerator
  }
  Client --> Config
  Client --> SseMethods
  SseMethods --> ServerSentEventsResult
  RequestOptions --> Config
  ServerSentEventsOptions --> ServerSentEventsResult
Loading

Class diagram for updated API response and error types

classDiagram
  class AuthJwtLoginResponses {
    +200: BearerResponse
  }
  class AuthJwtLoginErrors {
    +400: ErrorModel
    +422: HttpValidationError
  }
  class RegisterRegisterResponses {
    +201: UserRead
  }
  class RegisterRegisterErrors {
    +400: ErrorModel
    +422: HttpValidationError
  }
  class ResetForgotPasswordResponses {
    +202: unknown
  }
  class ResetForgotPasswordErrors {
    +422: HttpValidationError
  }
  class ResetResetPasswordResponses {
    +200: unknown
  }
  class ResetResetPasswordErrors {
    +400: ErrorModel
    +422: HttpValidationError
  }
  class VerifyRequestTokenResponses {
    +202: unknown
  }
  class VerifyRequestTokenErrors {
    +422: HttpValidationError
  }
  class VerifyVerifyResponses {
    +200: UserRead
  }
  class VerifyVerifyErrors {
    +400: ErrorModel
    +422: HttpValidationError
  }
  class UsersCurrentUserResponses {
    +200: UserRead
  }
  class UsersCurrentUserErrors {
    +401: unknown
  }
  class UsersDeleteUserResponses {
    +204: void
  }
  class UsersDeleteUserErrors {
    +401: unknown
    +403: unknown
    +404: unknown
    +422: HttpValidationError
  }
  class UsersUserResponses {
    +200: UserRead
  }
  class UsersUserErrors {
    +401: unknown
    +403: unknown
    +404: unknown
    +422: HttpValidationError
  }
  class UsersPatchUserResponses {
    +200: UserRead
  }
  class UsersPatchUserErrors {
    +400: ErrorModel
    +401: unknown
    +403: unknown
    +404: unknown
    +422: HttpValidationError
  }
Loading

Class diagram for new and updated data models (types.gen.ts)

classDiagram
  class BearerResponse {
    +access_token: string
    +token_type: string
  }
  class BodyAuthResetForgotPassword {
    +email: string
  }
  class BodyAuthResetResetPassword {
    +token: string
    +password: string
  }
  class BodyAuthVerifyRequestToken {
    +email: string
  }
  class BodyAuthVerifyVerify {
    +token: string
  }
  class ErrorModel {
    +detail: string | object
  }
  class HttpValidationError {
    +detail: Array<ValidationError>
  }
  class ItemCreate {
    +name: string
    +description: string | null
    +quantity: number | null
  }
  class ItemRead {
    +name: string
    +description: string | null
    +quantity: number | null
    +id: string
    +user_id: string
  }
  class PageItemRead {
    +items: Array<ItemRead>
    +total: number | null
    +page: number | null
    +size: number | null
    +pages: number | null
  }
  class UserCreate {
    +email: string
    +password: string
    +is_active: boolean | null
    +is_superuser: boolean | null
    +is_verified: boolean | null
  }
  class UserRead {
    +id: string
    +email: string
    +is_active: boolean
    +is_superuser: boolean
    +is_verified: boolean
  }
  class UserUpdate {
    +password: string | null
    +email: string | null
    +is_active: boolean | null
    +is_superuser: boolean | null
    +is_verified: boolean | null
  }
  class ValidationError {
    +loc: Array<string | number>
    +msg: string
    +type: string
  }
  class Login {
    +grant_type: string | null
    +username: string
    +password: string
    +scope: string
    +client_id: string | null
    +client_secret: string | null
  }
Loading

File-Level Changes

Change Details Files
Bump dependencies and adjust scripts
  • Bumped project version to 0.0.7
  • Upgraded @hey-api/openapi-ts, client-axios/fetch, added axios dependency
  • Updated watcher script to use pnpm run
package.json
watcher.js
Ignore generated client in ESLint and update OpenAPI config
  • Added app/openapi-client/** to ESLint ignore list
  • Switched openapi-ts.config to use plugins setting for @hey-api/client-axios
eslint.config.mjs
openapi-ts.config.ts
Fix client entry points
  • Adjusted exports order in app/openapi-client/index.ts
  • Updated import path in lib/clientConfig.ts to use new client.gen
app/openapi-client/index.ts
lib/clientConfig.ts
Regenerate OpenAPI client code to new generator API
  • Regenerated types with camelCase names, JSDoc comments, and separate Responses/Errors maps
  • Updated sdk functions to use new Options type, set responseType, headers and security arrays
  • Added core modules (bodySerializer, pathSerializer, params, utils, SSE) and a custom Axios-based client implementation
app/openapi-client/types.gen.ts
app/openapi-client/sdk.gen.ts
app/openapi-client/core/**
app/openapi-client/client/**
app/openapi-client/client/utils.gen.ts

Possibly linked issues

  • #ISSUE_ID_UNKNOWN: The PR updates the @hey-api/openapi-ts library from version 0.60.1 to 0.83.1, directly addressing the issue's goal.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • This PR combines dependency bumps, ESLint config updates, and a massive auto-generated client—consider splitting the config and dependency changes from the generated code into separate commits or PRs to make reviews clearer.
  • The watcher script was updated to use pnpm but other scripts still reference npm; please standardize your package manager calls across all scripts to avoid confusion.
  • You’ve added openapi-client/** to ESLint ignores, but you may also want to exclude this folder in tsconfig or IDE settings so generated types aren’t unnecessarily type-checked during development.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- This PR combines dependency bumps, ESLint config updates, and a massive auto-generated client—consider splitting the config and dependency changes from the generated code into separate commits or PRs to make reviews clearer.
- The watcher script was updated to use pnpm but other scripts still reference npm; please standardize your package manager calls across all scripts to avoid confusion.
- You’ve added openapi-client/** to ESLint ignores, but you may also want to exclude this folder in tsconfig or IDE settings so generated types aren’t unnecessarily type-checked during development.

## Individual Comments

### Comment 1
<location> `nextjs-frontend/app/openapi-client/client/types.gen.ts:199` </location>
<code_context>
+> &
+  Omit<TData, "url">;
+
+export type OptionsLegacyParser<
+  TData = unknown,
+  ThrowOnError extends boolean = boolean,
</code_context>

<issue_to_address>
**issue (complexity):** Consider introducing a ReplaceProps utility type to flatten the complex conditional type definitions for OptionsLegacyParser and Options.

```suggestion
// Introduce a small helper to avoid deeply nested branches:
type ReplaceProps<Base, Overrides> = Omit<Base, keyof Overrides> & Overrides;

// Then you can collapse the 4-branch `OptionsLegacyParser` into a single union:
export type OptionsLegacyParser<
  TData = unknown,
  ThrowOnError extends boolean = boolean
> = ReplaceProps<RequestOptions<unknown, ThrowOnError>, TData>;

// Optionally also simplify `Options` the same way:
export type Options<
  TData extends TDataShape = TDataShape,
  ThrowOnError extends boolean = boolean,
  TResponse = unknown,
> = ReplaceProps<
  RequestOptions<TResponse, ThrowOnError>,
  Omit<TData, 'url'>
>;
```

Steps:
1. Add the `ReplaceProps` utility at the top.
2. Replace the conditional `OptionsLegacyParser` definition with the single‐line version above.
3. Update `Options` similarly if desired.

This preserves all branches (you can still pass `{ body }` or `{ headers }`) without the nested `extends` logic.
</issue_to_address>

### Comment 2
<location> `nextjs-frontend/app/openapi-client/client/utils.gen.ts:23-65` </location>
<code_context>
  const querySerializer = (queryParams: T) => {
    const search: string[] = [];
    if (queryParams && typeof queryParams === "object") {
      for (const name in queryParams) {
        const value = queryParams[name];

        if (value === undefined || value === null) {
          continue;
        }

        if (Array.isArray(value)) {
          const serializedArray = serializeArrayParam({
            allowReserved,
            explode: true,
            name,
            style: "form",
            value,
            ...array,
          });
          if (serializedArray) search.push(serializedArray);
        } else if (typeof value === "object") {
          const serializedObject = serializeObjectParam({
            allowReserved,
            explode: true,
            name,
            style: "deepObject",
            value: value as Record<string, unknown>,
            ...object,
          });
          if (serializedObject) search.push(serializedObject);
        } else {
          const serializedPrimitive = serializePrimitiveParam({
            allowReserved,
            name,
            value: value as string,
          });
          if (serializedPrimitive) search.push(serializedPrimitive);
        }
      }
    }
    return search.join("&");
  };
  return querySerializer;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
  return (queryParams: T) => {
      const search: string[] = [];
      if (queryParams && typeof queryParams === "object") {
        for (const name in queryParams) {
          const value = queryParams[name];

          if (value === undefined || value === null) {
            continue;
          }

          if (Array.isArray(value)) {
            const serializedArray = serializeArrayParam({
              allowReserved,
              explode: true,
              name,
              style: "form",
              value,
              ...array,
            });
            if (serializedArray) search.push(serializedArray);
          } else if (typeof value === "object") {
            const serializedObject = serializeObjectParam({
              allowReserved,
              explode: true,
              name,
              style: "deepObject",
              value: value as Record<string, unknown>,
              ...object,
            });
            if (serializedObject) search.push(serializedObject);
          } else {
            const serializedPrimitive = serializePrimitiveParam({
              allowReserved,
              name,
              value: value as string,
            });
            if (serializedPrimitive) search.push(serializedPrimitive);
          }
        }
      }
      return search.join("&");
    };

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>

### Comment 3
<location> `nextjs-frontend/app/openapi-client/client/utils.gen.ts:138` </location>
<code_context>
    query: !options.paramsSerializer ? options.query : undefined,

</code_context>

<issue_to_address>
**suggestion (code-quality):** Invert ternary operator to remove negation ([`invert-ternary`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/invert-ternary))

```suggestion
    query: options.paramsSerializer ? undefined : options.query,
```

<br/><details><summary>Explanation</summary>Negated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By inverting the ternary condition and swapping the
expressions we can simplify the code.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@andersonresende andersonresende self-requested a review October 24, 2025 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant