跳到导航

Changelog

4.22.3

(fix): Honor package-prefix and package-layout for local-file-system output when the CLI requests a full project (e.g. --generate-tests, --package, or self-hosted SDKs). Previously these were dropped when converting the local-file-system config, so the root package fell back to com.<org>.<api> instead of the configured prefix. Full-project local output now also writes sources at their full package path (src/main/java/com/acme/...) instead of stripping the prefix from the directory.

4.22.2

(fix): RetryInterceptor now applies the client timeout to each attempt individually instead of to the whole retry loop. Previously a Retry-After wait as long as the timeout (e.g. Retry-After: 60 with the default 60s timeout) cancelled the call during the backoff sleep and surfaced IOException: Canceled instead of retrying or returning the received 429. The call timeout is paused while waiting for the backoff and restarted for each retry attempt, so a call that retries may now take up to timeout * (maxRetries + 1) plus the backoff waits.

4.22.1

(fix): Closing the root client (or ClientOptions.close()) now disconnects any WebSocket clients that are still connected before the SDK-owned OkHttp dispatcher is shut down, so they stop reconnecting cleanly instead of failing asynchronously with InterruptedIOException: executor rejected. ClientOptions exposes isClosed(); WebSocket connect/reconnect attempts made after close, as well as OkHttpWebSocketFactory.create(...) when constructed with a closed-check, fail fast with IllegalStateException("root client has been closed").

4.22.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.

(fix): Fix the generated ReconnectingWebSocketListener connection-timeout message, which was missing the closing parenthesis after the retry attempt number (e.g. ... milliseconds (retry attempt #2).

4.21.2

(fix): RetryInterceptor no longer discards an API response it has already received (e.g. a 429) when a later retry attempt fails, such as when the call timeout expires mid-retry. The previous response is buffered and returned instead of surfacing a generic IOException.

4.21.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.

4.21.0

(feat): Generated root clients (sync and async) now implement AutoCloseable. close() shuts down the underlying OkHttpClient’s dispatcher executor and evicts its connection pool, but only when the SDK created that OkHttpClient itself — a client supplied via Builder.httpClient(...) is left running, since the caller owns its lifecycle. This lets short-lived applications (e.g. CLIs, or code that finishes after using WebSockets) release the client’s background threads instead of relying on JVM shutdown.

4.20.0

(feat): Object types with xml encoding metadata (e.g. TwiML defined via OpenAPI xml objects) now implement XmlSerializable with toXml() and a static fromXml(String) parser, backed by new core XmlWriter/XmlReader utilities. Builders gain per-child-element methods (e.g. Response.builder().say(...)) and undiscriminated child unions dispatch fromXml by element name. Builder.fromXml(String) returns a populated builder, unknown child elements are preserved as XmlElements (readable via getAdditionalChildren(), addable via addChild(...)) and round-tripped by toXml(), and very large objects that use a builder-based constructor also get fromXml. Types without xml metadata are unchanged.

4.19.3

(fix): Generated ReconnectingWebSocketListener now acknowledges peer-initiated close frames by overriding onClosing, so OkHttp completes the close handshake and onClosed (and the public disconnect lifecycle) fires for server-initiated closes. A no-status close (local sentinel 1005) is acknowledged with 1000, since 1005 is not a wire-valid close code. The reconnect decision is exposed as a protected boolean shouldReconnectAfterClose(WebSocket, int, String) hook (default unchanged: code != 1000) so resource-specific subclasses can treat a protocol-established terminal close as final. Adds send(String, Consumer<WebSocket>) / sendBinary(ByteString, Consumer<WebSocket>) overloads that report which socket directly accepted a message (not invoked for queued or dropped messages).

4.19.2

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

4.19.1

(fix): Honor an endpoint’s retries: {disabled: true} configuration (the x-fern-retries OpenAPI extension). A call to such an endpoint tags its request with a max-retries override of zero, so it bypasses automatic retries regardless of the client-wide ClientOptions.maxRetries or a per-request RequestOptions.maxRetries. Endpoints without the configuration are unchanged.

4.19.0

(fix): With respect-optional-request-body enabled, a call that leaves out an optional request body now passes a null body to OkHttp instead of an empty one, so the request carries no body at all. The methods OkHttp requires a body for (POST, PUT, PATCH) still send an empty body, which is what endpoints with no request body at all already send.

(feat): Add a respect-optional-request-body option. When enabled, an endpoint whose request body the API does not require also gets an overload without the body parameter, and calling that overload sends no body. The body parameter keeps its own type, so alpha(String id, Body body) gains a sibling alpha(String id) rather than becoming alpha(String id, Optional<Body> body). Examples that supply no body render as client.alpha(id). That call also leaves out the Content-Type header, which now only goes out when a body does. The option defaults to false, so existing signatures and snippets are unchanged.

4.18.2

(fix): Build an empty request body in snippets for an endpoint example that omits a body the wrapped request requires, instead of leaving the builder’s required body stage unset.

4.18.1

(fix): Fix the generated OAuth token supplier when the get-token request has required properties other than the client credentials. The builder calls are now ordered by the request’s required properties, so the staged builder’s stages are satisfied in order, and hardcoded values (such as grant_type) are written using the property’s type, which means an enumerated grant_type gets the generated enum constant instead of a string literal.

4.18.0

(feat): Add support for the FERN_JAVA_SKIP_FORMATTING environment variable. When set to a truthy value (1, true, yes, or on), the generator skips the ./gradlew :spotlessApply pass that normally runs after code generation, so generation makes no Gradle invocation at all. This unblocks restricted networks that cannot reach the Gradle distribution or plugin repositories, and shortens generation time.

4.17.1

(fix): Fixed wire tests generated for APIs with auth: any combining Basic and OAuth schemes. Tests no longer assert both a Bearer and a Basic Authorization header on the same request; only the OAuth Bearer assertion is emitted since the client sends the OAuth token when OAuth credentials are configured.

4.17.0

(feat): Add opt-in allowUserAgentAppInfo config. When enabled, the generated client’s builder exposes an appInfo(name, version, comment) option whose product token is appended to the User-Agent header the SDK would otherwise send ({sdk}/{version} ... {name}/{version} ({comment})), following RFC 9110. Disabled by default, so existing generated output is unchanged, and it composes with includePlatformHeaders, the runtime-version jar-manifest path, the configured user-agent template value, and the default {coordinate}/{version}. Caller-supplied values are trimmed and sanitized (name/version percent-encoded to RFC 7230 tchars; comment delimiters, control characters and any non-ASCII characters percent-encoded as UTF-8 bytes so OkHttp’s header validation never rejects them), so untrusted values cannot inject header content. Still overridable by an explicit User-Agent and suppressed by omit-fern-headers.

4.16.0

(feat): Add an opt-in runtime-version config flag. When enabled, the SDK version reported in the telemetry headers (X-Fern-SDK-Version and the version segment of User-Agent) is resolved at runtime from the jar manifest’s Implementation-Version attribute instead of being baked in as a literal at generation time. The generated build.gradle records the project version in the jar manifest, so an external tool such as release-please only has to rewrite a single version line for the reported version to track the actually-published artifact — rather than a version the SDK may never publish. Falls back to the generation-time version when the manifest attribute is absent (e.g. running from unpackaged classes). Disabled by default, so existing generated output is unchanged, and subject to omitFernHeaders.

4.15.5

(fix): Resolve the X-Fern-SDK-Name header from the configured Maven coordinate in GitHub output mode. Previously the header was read from the (Fiddle-synthesized) publish config, so it emitted com.<org>.fern:<workspace>-sdk instead of the coordinate the user configured under output.coordinate, leaving it inconsistent with the User-Agent product token. The header now reads output.mode.github.publishInfo.maven.coordinate, which is populated for both remote and --local generation. Also emits X-Fern-SDK-Version in cases where a coordinate resolves without a version previously being set.

4.15.4

(fix): Global headers now honor their env and client-default values. The builder initializes the header from the environment variable when set, otherwise the client default, and an explicitly provided value still takes precedence. Previously a global header was only sent when the caller set it explicitly.