2.76.3

(fix): The README “Environments” usage example now passes the client options via the clientOptions: named argument so the generated snippet compiles. The root client constructor’s first positional parameter is the auth token string, so the previous new Client(new ClientOptions { ... }) snippet passed ClientOptions where a string? token was expected.

2.76.2

(fix): A generated nested type whose name matches the SDK’s root namespace segment now emits global::-qualified references. Previously such a nested type shadowed the namespace root within its enclosing type’s body, so references like Acme.Api.SomeType resolved to the nested type and failed to compile. The global:: qualifier is applied only to references written inside the enclosing type where the shadow is visible, so unrelated references to the same root segment elsewhere in the SDK are left unqualified.

2.76.1

(fix): Endpoints without a request wrapper (no request object, a request that is just a body, or a bytes request) now send service- and endpoint-level headers whose types are literals (e.g. Accept-Encoding: literal<"gzip">). Previously these headers were silently dropped because there was no request object to carry them.

2.75.2

(fix): Fix a compile error in the generated OAuthTokenProvider when the token endpoint’s expires-in response property is optional. The provider now null-checks the value before computing the token expiry instead of passing a nullable number to DateTime.AddSeconds.

2.75.1

(fix): Wire OAuth client-credentials authentication into the root client when the OAuth scheme is not the first scheme in the API’s auth configuration (e.g. auth: any with basic auth listed before OAuth). Previously the OAuth token provider was only generated when OAuth was the first auth scheme, so the root client silently fell back to the other schemes and never used the OAuth credentials. When both an OAuth and an inferred auth scheme are present, the provider-based scheme that appears first in the auth configuration is used.

2.76.0

(fix): Add an opt-in dedupe-union-base-properties configuration flag (default off) that stops duplicating a discriminated union’s base properties on its samePropertiesAsObject variant leaves. The decision is read from the IR fact ObjectTypeDeclaration.deferredUnionBaseProperties (computed once in the IR with structural type equality and an exclusive-variant guard), so the generator never re-derives it. When enabled, the union envelope owns the shared base properties, the variant leaf class and its example initializers omit them, and the union’s JSON reader strips union-owned properties before deserializing a variant. Off by default, so existing generated output is unchanged; the default is expected to flip in a future major version with a migration.

2.75.0

(feat): Add support for auto-generating an Idempotency-Key header on generated SDK clients, driven by the IR. When sdkConfig.idempotencyKeyGeneration is present (configured once via the auto-generate-idempotency-key generator config key and resolved by the CLI), the SDK attaches an idempotency-key request header whose value is a freshly generated UUIDv4 (System.Guid.NewGuid().ToString()) at request time. The wire header name and the eligible HTTP methods come from the IR, so behavior is consistent across every generator. A caller-provided value always wins: a declared idempotency header or a header supplied through request-options takes precedence, and the generated UUID is only a fallback. The header is only injected on the eligible methods. Disabled by default, so existing generated output is unchanged.

2.74.0

(feat): Add support for server URL variables (region/edge routing). When an API’s servers declare URL variables (e.g. https://api.{region}.example.com), each variable is now exposed as an optional string property on ClientOptions (idiomatic PascalCase, e.g. Region). Variable names that collide with an existing client option are prefixed with ServerUrl (e.g. an environment variable becomes ServerUrlEnvironment). When set at construction time, the values are interpolated into the environment base URL(s), falling back to each variable’s default otherwise. Explicit BaseUrl or Environment options take precedence, and interpolation fails clearly when a required variable has neither a client option nor a default.

2.73.2

(fix): Enable automatic response decompression on the default HttpClient. The default client is now created with an HttpClientHandler configured with AutomaticDecompression (DecompressionMethods.All on .NET 5+, GZip | Deflate on older targets), so responses with a Content-Encoding of gzip or deflate are decompressed transparently — including when an Accept-Encoding request header is set explicitly by the API spec. User-supplied HttpClients provided via ClientOptions are not modified.

2.73.1

(fix): Make the structured User-Agent (emitted when includePlatformHeaders is enabled) comply with the RFC 7230 token grammar. The runtime token is now dotnet instead of .NET, since a leading dot is not a valid token character (e.g. dotnet/8.0.4). The architecture label is also normalized so the 64-bit x86 aliases (x64, amd64, x86_64) all report as the canonical x86_64.

2.73.0

(feat): Add opt-in support for a structured User-Agent header on generated SDK clients of the form {sdkName}/{sdkVersion} ({os}; {arch}) {runtime}/{runtimeVersion} (e.g. my-sdk/1.2.0 (linux; x64) .NET/8.0.4). The OS, architecture, and runtime version are resolved at runtime via System.Runtime.InteropServices.RuntimeInformation and System.Environment. This is gated behind a new include-platform-headers config option and is disabled by default, so existing generated output is unchanged. When enabled it remains subject to the omit-fern-headers config option.

2.72.2

(fix): Make each scheme’s credentials optional under any-composed auth. Previously, with a multi-scheme auth: any: [...] config the generated client treated OAuth (and other) credentials as unconditionally required at construction, so a caller who only wanted API-key auth could not instantiate the client. Credentials now fall back to environment variables without throwing, and the OAuth/inferred token provider and auth headers are only set up when that scheme’s credentials are present.

2.72.1

(chore): Bump the bundled @fern-api/generator-cli to 0.9.44 so every local-only commit is signed when pushing to GitHub, not just HEAD. Replay branches contain multiple commits (e.g. [fern-generated] + [fern-replay]); previously only the HEAD commit was recreated via the GitHub API and signed, leaving earlier commits on the PR unverified.

2.72.0

(feat): Add a default-timeout-in-milliseconds config option to the C# SDK generator for expressing the default network timeout in milliseconds (mapping to .NET’s TimeSpan). The generated ClientOptions.Timeout is now computed from milliseconds (or Timeout.InfiniteTimeSpan when set to "infinity"). The default-timeout-in-seconds option is now deprecated but remains fully backwards compatible: when only the seconds key is set, it is converted to milliseconds. The new key takes precedence when both are set.

2.71.2

(fix): Fix mock-server tests and XML-doc <example> snippets calling client methods with path parameters in the wrong order (CS1503) when a user-authored example lists its path-parameters in a different order than the URL path template. The generated method signature follows the IR’s canonical (URL-template) order, but the snippet writer was consuming the example’s path-parameters positionally in the author’s declared order. Example values are now bound to each parameter by name and emitted in the endpoint’s canonical path-parameter order, matching the generated signature.

2.71.1

(fix): Fix SSE stream reconnection correctness to match the reference implementation: (1) Do not reconnect when no terminator is configured (the client cannot distinguish a completed stream from a dropped connection). (2) Apply a default 1-second backoff between reconnect attempts when the server sends no retry: directive (previously zero delay). (3) Use the last dispatched event ID for reconnection rather than the last parsed id, preventing silent event loss on mid-event drops. (4) Treat reconnect function failures as consumed attempts; throw IOException with the last failure as InnerException when the cap is exhausted, instead of silently truncating the stream. (5) Let OperationCanceledException propagate immediately from reconnectFn instead of swallowing it as a retry attempt. (6) Dispose the old HTTP response only after a new one is successfully obtained, preventing ObjectDisposedException on retry.

2.71.0

(feat): Add opt-in SSE stream reconnection for resumable endpoints. When an SSE endpoint is marked as resumable, the generated SDK automatically reconnects using the Last-Event-ID header. New RequestOptions fields: MaxStreamReconnectAttempts, DisableStreamReconnection.

2.70.0

(feat): Add support for undocumented/extra parameters: AdditionalQueryParameters from RequestOptions are now applied to all endpoints (previously only endpoints with defined query parameters would merge them). Also add ADDITIONAL_BODY_PROPERTIES feature to README generation.

2.69.2

(fix): Fix shell injection code scanning alert in OIDC publish workflow by passing API key through env block instead of direct interpolation.

2.69.1

(fix): Fix generated wire tests failing to compile when a header, query parameter, or auth header example value contains characters that are special inside a C# string literal (e.g. double quotes, backslashes, or control characters). These values are now emitted through escapeForCSharpString in the mock-server .WithHeader(...) / .WithParam(...) matchers instead of being interpolated raw into a double-quoted string.