Skip to content

Releases: ardatan/feTS

March 25, 2026

25 Mar 12:07
a78dae1

Choose a tag to compare

fets@0.8.6

Patch Changes

  • #3650
    db80dbc
    Thanks @copilot-swe-agent! - Allow optional request
    bodies in OpenAPI spec by respecting TypeBox Type.Optional modifier

    Previously, the OpenAPI plugin hardcoded requestBody.required = true for all JSON and formData
    request bodies, making it impossible to declare optional bodies using Type.Optional<...> or
    similar patterns from TypeBox.

    The plugin now checks for the TypeBox OptionalKind symbol on the schema and sets
    requestBody.required accordingly. Non-TypeBox schemas and non-optional schemas continue to
    produce required: true (preserving backward compatibility), while schemas wrapped with
    Type.Optional(...) correctly produce required: false.

    router.route({
      path: '/example',
      method: 'POST',
      schemas: {
        request: {
          json: Type.Optional(Type.Object({ name: Type.String() }))
        }
      },
      handler: () => Response.json({ ok: true })
    })
    // → requestBody.required === false in the generated OpenAPI spec
  • #3662
    8c5d3e0
    Thanks @copilot-swe-agent! - Fix "Type of property
    circularly references itself" error with arrays of recursive objects

    Schemas where a recursive type is referenced through an array property (e.g.
    children: { type: 'array', items: { $ref: '#/components/schemas/Node' } }) previously triggered
    TypeScript error TS2615 when used with createClient or the OASModel / OASOutput /
    OASJSONResponseSchema helpers.

    The root cause was in the Circular<T> type helper, which only detected self-references via
    direct property values (child: Node) but not through array items (children: Node[]). After
    NormalizeOAS resolves $refs it injects a $id field onto resolved schemas, making array items
    a subtype of the parent rather than the identical type. The existing equality-based check
    therefore returned false for the array case, allowing json-schema-to-ts to try to expand the
    circular type and hit TS2615.

    A new ArrayItemValue<T> helper extracts the items schema from an array-typed JSON schema. The
    Circular<T> check now additionally tests whether any array-property's items extend the parent
    schema, correctly identifying circular array references and disabling the problematic deserializer
    expansion.

    Before (broken):

    // Node.children is an array of Node — triggered TS2615
    const client = createClient<NormalizeOAS<typeof oas>>({})
    await client['/tree'].get() // Error: Type of property 'children' circularly references itself

    After (fixed):

    const client = createClient<NormalizeOAS<typeof oas>>({})
    const res = await client['/tree'].get()
    if (res.ok) {
      const body = await res.json()
      body.children?.[0]?.children?.[0]?.number // correctly typed as number | undefined
    }
  • #3665
    5fd3022
    Thanks @copilot-swe-agent! - Fix "Type of property
    circularly references itself" error for mutually-recursive schemas (e.g. Argo Workflows OpenAPI
    spec)

    Large OpenAPI specs such as Argo Workflows contain mutually-recursive schema references (e.g.
    Template → DAGTemplate → DAGTask → Template). These schemas caused TypeScript error TS2615 when
    used with OASModel, OASOutput, OASJSONResponseSchema, or createClient.

    The root cause was in the Circular<T> type helper, which detected only:

    1. Direct self-references (child: Node where Node.child resolves back to the same Node type)
    2. Array self-references added in a previous fix (children: Node[])

    It did not detect indirect mutual recursion (Schema A → Schema B → Schema A), because the
    recursive type check Circular<PropertyValue<A>> eventually calls Circular<A> again, causing
    TypeScript to hit its recursion limit and silently fail, leaving the deserializer enabled and
    triggering TS2615 inside json-schema-to-ts.

    The fix extends Circular<T> to also return true when any property of the schema is a
    resolved $ref — identified by the presence of a $id field that NormalizeOAS injects.
    Such schemas were resolved from $ref entries in the original OpenAPI document and may
    participate in complex circular reference chains. Disabling the deserializer expansion for these
    schemas avoids the TS2615 error.

    Before (broken):

    // Template → DAGTemplate → DAGTask → Template caused TS2615
    type NormalizedArgo = NormalizeOAS<typeof argoWorkflowsOAS>
    type TemplateType = OASModel<NormalizedArgo, 'Template'> // Error: TS2615
    const client = createClient<NormalizedArgo>({})
    await client['/workflow'].get() // Error: TS2615

    After (fixed):

    type NormalizedArgo = NormalizeOAS<typeof argoWorkflowsOAS>
    type TemplateType = OASModel<NormalizedArgo, 'Template'> // Works!
    const client = createClient<NormalizedArgo>({})
    const res = await client['/workflow'].get() // Works!
    if (res.ok) {
      const body = await res.json()
      body.dag?.tasks?.[0]?.name // correctly typed as string | undefined
    }
  • #3652
    4c0976b
    Thanks @copilot-swe-agent! - Fix object types with
    array type (e.g. ["object", "null"]) being inferred as undefined

    OpenAPI 3.1 schemas that declare a nullable object using an array type such as
    "type": ["object", "null"] were incorrectly inferred as undefined in the feTS client instead
    of resolving to the correct union type (e.g.
    { url: string; name: string; size: number } | null).

    The root cause was in the FixJSONSchema type pipeline:

    • FixMissingTypeObject unconditionally added & { type: 'object' } to any schema with
      properties, even when type was already set. For type: ["object", "null"] this produced
      { type: ["object", "null"] } & { type: 'object' }{ type: never }, causing
      json-schema-to-ts to yield undefined.
    • FixMissingAdditionalProperties only matched type: 'object' (string literal), so schemas with
      array types never received the required additionalProperties: false injection.

    Both helpers have been updated to correctly handle array-style type declarations.

  • #3649
    bce414f
    Thanks @copilot-swe-agent! - Fix client sending HTTP
    methods in lowercase (e.g. patch instead of PATCH). The client now normalizes all HTTP methods
    to uppercase before sending the request.

  • #3653
    742c313
    Thanks @copilot-swe-agent! - Fix required query
    parameters becoming optional when mixed with header parameters in the client type generation.
    Previously, when an endpoint had both query and header parameters, required query parameters were
    incorrectly typed as optional. The fix correctly checks whether any parameter of the specific type
    (query or header) is marked as required: true instead of using a tuple check across all
    parameter types.

  • #3651
    3d17b72
    Thanks @copilot-swe-agent! - fix: apply
    encodeURIComponent to URL path parameters in createClient

    Previously, path parameters were substituted into the URL as-is, which could result in malformed
    URLs when the parameter values contained characters such as spaces, slashes, question marks, or
    non-ASCII characters.

    For example, passing { id: 'hello world' } to /todo/{id} would produce /todo/hello world
    instead of /todo/hello%20world.

    With this fix, all path parameter values are now passed through encodeURIComponent before being
    substituted into the URL, ensuring that the generated request URL is always valid and correctly
    encoded.

  • #3654
    a313e10
    Thanks @copilot-swe-agent! - Add use() method for
    router composition and merging

    Routers can now be composed together using the .use() method, allowing you to split routes
    across multiple files and merge them into a parent router.

    // users-router.ts
    const usersRouter = createRouter().route({
      path: '/users',
      method: 'GET',
      handler: () => Response.json({ users: [] })
    })
    
    // app.ts
    const app = createRouter()
      .use(usersRouter) // merge at existing paths
      .use('/api', anotherRouter) // merge under a prefix

    The .use() method supports:

    • Merging a sub-router at its existing paths
    • Merging with a path pref...
Read more

March 05, 2025

05 Mar 15:26
2f2cc1a

Choose a tag to compare

fets@0.8.5

Patch Changes

November 15, 2024

15 Nov 10:00
ebf8384

Choose a tag to compare

fets@0.8.4

Patch Changes

August 16, 2024

16 Aug 01:55
1352d40

Choose a tag to compare

fets@0.8.3

Patch Changes

August 07, 2024

07 Aug 16:22
25d5080

Choose a tag to compare

fets@0.8.2

Patch Changes

June 11, 2024

11 Jun 08:30
91936d7

Choose a tag to compare

fets@0.8.1

Patch Changes

March 25, 2024

25 Mar 10:28
bed5e5d

Choose a tag to compare

fets@0.8.0

Minor Changes

March 14, 2024

14 Mar 02:43
8a95054

Choose a tag to compare

fets@0.7.2

Patch Changes

January 02, 2024

02 Jan 11:45
0a657ed

Choose a tag to compare

fets@0.7.1

Patch Changes

December 22, 2023

22 Dec 11:20
0a15c20

Choose a tag to compare

fets@0.7.0

Minor Changes

Patch Changes