Skip to navigation

Changelog

3.97.1

(fix): Fix generated WebSocket socket classes registering their open/message/close/error forwarding listeners twice when connect() is called after construction (the standard new Socket(...).connect() usage). ReconnectingWebSocket gains a hasEventListener(type, listener) method and connect() only registers each forwarding listener if it is not already attached, so every consumer .on() callback fires exactly once per event while close() followed by connect() continues to work.

3.97.0

(feat): Generate the shared WebhooksHelper from the API-wide api.settings.webhook-signature setting in generators.yml (IR sdkConfig.webhookSignatureVerification). The helper is emitted even when the API definition models no webhooks; webhook-specific signature overrides still produce their own named helpers.

3.96.3

(fix): Wire tests for paginated endpoints whose page property is nested in the request body (e.g. $request.options.offset or $request.options.pagination.cursor) no longer fail on getNextPage(). The generated pager creates the parent object (options) when the example omits it, and the mock server’s jsonBody matcher treated that new parent as an unexpected field even though the nested leaf was listed in ignoredFields, so the second request never matched the mock and failed with a connection-refused error. The matcher now ignores a parent object that is absent from the expected body when every leaf inside it is an ignored field.

3.96.2

(fix): The generated OAuth wire-test mock (tests/wire/mockAuth.ts) now expects the grant_type the generated OAuthAuthProvider actually sends. When the token endpoint models grant_type as a plain (optional) string and the example omits it, the provider sends grant_type: "client_credentials" but the mock previously only matched the example body, so the token request never matched and every authenticated wire test failed with a connection-refused error.

3.96.1

(chore): Bump bundled @fern-api/generator-cli to 0.10.1. Auto-versioned MAJOR/MINOR bumps no longer produce a version-only changelog.md block when the AI analysis returns an empty changelog entry; the PR description, version bump reason, or commit message body is used instead.

3.96.0

(feat): Object types with XML encoding metadata (e.g. TwiML schemas imported from an OpenAPI xml object) are now generated as classes with toXml(), a static fromXml() parser, and a fluent Builder (including Builder.fromXml(xml).build() and per-child methods such as response.say(...)). Element names, attributes, text bodies, nested/union children, wrapped lists, list separators, namespaces and prefixes are honored; undeclared attributes and child elements are preserved as additionalAttributes / additionalChildren so documents round-trip. Parsing is strict (root name, scalar/enum validation) and rejects DOCTYPE declarations. Non-XML types are unaffected and the XML runtime is only emitted when needed.

3.95.1

(fix): TypeScript dynamic snippets honor flattenRequestParameters by spreading referenced object bodies instead of emitting body: {...}, and nest multi-auth constructor options under the camelCase auth scheme key regardless of noSerdeLayer or retainOriginalCasing.

3.95.0

(feat): SDKs now read the base URL from the environment variable configured via base-url-env / x-fern-base-url-env when no baseUrl or environment option is passed, respecting guardProcessEnvAccess for the environment-variable read.

3.94.2

(fix): A union member whose discriminant value collides with a JavaScript built-in no longer has the disambiguation prefix applied to the string literal. A branch with condition_type: "Date" emitted conditionType: "globalThis.Date" — so the property could not be typed without a cast, since the API expects "Date", and with noSerdeLayer: false the serializer’s inferred discriminant no longer matched the declared literal and the package failed to compile. Qualification exists to disambiguate a shadowed type reference; a literal is a value, and rewriting one changes what the SDK sends. String literals are now skipped, which also covers builder expressions and visitor signatures, where the same rewrite could reach an object literal. Type references are unaffected: a sibling property typed Date still becomes globalThis.Date.

3.94.1

(fix): Fix generated wire tests for cursor, URI, and path pagination when the example response uses an empty string to indicate there is no next page. Terminal URI and path continuations are preserved in the mocked response, and the tests skip hasNextPage() and getNextPage() assertions, matching the generated pager.

3.94.0

(feat): Add a websocketHandlerMode config option ("replace" | "accumulate", defaults to "replace") for generated WebSocket Socket classes. With accumulate, multiple on() handlers for the same event are all kept and run in registration order instead of the last one replacing the previous. Generated sockets now also expose off(event, callback) to detach a handler in both modes. Defaults to replace, so generated output is unchanged unless the option is enabled.

3.93.1

(fix): The generated README now always includes a Pagination section (and pagination usage snippets) when the API has paginated endpoints, matching the client which always returns core.Page. Previously the section was dropped when the CLI ran without org information (e.g. fern generate --local without a FERN_TOKEN).

3.93.0

(feat): Add an opt-in esmOnly configuration flag. When enabled, the generated package ships only the existing ESM build: package.json is marked type: "module", the exports map only exposes the .mjs/.d.mts entry points, and the CommonJS build (tsconfig.cjs.json, build:cjs) is no longer generated. This avoids the dual package hazard for consumers who want a pure-ESM package. The default behavior (dual CJS + ESM output, including with outputEsm: true) is unchanged. esmOnly is incompatible with useLegacyExports and bundle.

3.92.0

(feat): Add a new exactOptionalPropertyTypes config option (default false) that makes the generated SDK compile cleanly under TypeScript’s exactOptionalPropertyTypes compiler option. When enabled, every optional property is emitted as prop?: T | undefined across model types, inlined request wrappers, client options, errors, and the core/ utilities, and the generated tsconfig files enable exactOptionalPropertyTypes so the generated package typechecks itself under the stricter mode. Previously this behavior was partially available only with noSerdeLayer: true; the new flag applies it uniformly, including when the serde layer is enabled.

3.91.0

(feat): Add the opt-in deepObjectMapQueryParameters configuration option. When enabled, query parameters typed as a map (e.g. map<string, string>, which is what an OpenAPI type: object + additionalProperties schema imports as) are handed to the query builder and serialized in deepObject form (?metadata[env]=prod) instead of being JSON-stringified (?metadata=%7B%22env%22...). Maps whose values are objects, nested maps, lists, sets, or date-times are supported too: with the serde layer enabled they are run through the generated schema first, so nested keys use wire names, sets become arrays, and dates are ISO strings (?metadata[env][created_at]=2026-09-04T00:00:00.000Z). Defaults to false, so existing SDKs are unaffected.

3.90.0

(feat): Add the packageJsonMergeStrategy option (shallow | deep, default shallow) controlling how packageJson overrides in generators.yml are merged into the generated package.json.

shallow is the existing behavior and remains the default: nested objects such as exports["."] are replaced wholesale by the override, so adding a single custom export condition drops the generated import/require/default conditions.

3.89.0

(feat): Add a guardProcessEnvAccess config option (boolean, defaults to false). When enabled, the generated header, bearer, basic and OAuth auth providers read environment variables through a typeof process !== "undefined" guard, so a missing credential surfaces the normal error instead of ReferenceError: process is not defined in runtimes without a Node process global (browsers/Vite, Cloudflare Workers, Deno). Defaults to false, so generated output is unchanged unless the option is enabled.

3.88.3

(fix): Respect custom OAuth token headers and prefixes for client credentials authentication.

3.88.2

(fix): Stop dropping the examples of endpoints whose request body is bytes or a file upload. The IR’s ExampleRequestBody cannot carry those bodies, so such examples read as bodyless and the endpoint lost its reference.md section, snippets and docs comments.

(fix): Positional path parameters that an example does not supply are now rendered with their client-default value instead of undefined, so generated snippets typecheck.

3.88.1

(fix): Endpoints that disable retries (x-fern-retries: { disabled: true } in OpenAPI, or retries: { disabled: true } in a Fern definition) now always emit maxRetries: 0, overriding both client-level and request-level maxRetries. Previously this configuration was only honored by the Python SDK generator and was silently ignored in TypeScript.