Changelog
2.83.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 snippets and generated tests.
2.83.1
(fix): Honor the x-fern-retries: { disabled: true } extension (retries: { disabled: true } in a Fern
definition) at the endpoint level. Requests for those endpoints are now sent exactly once, even when
the client or the per-request options configure retries.
2.83.0
(feat): Added a generate-documentation-file config option (default true) so the
generated csproj emits XML documentation and the published NuGet package ships
lib/<tfm>/<Namespace>.xml, giving consumers IntelliSense. CS1591 is
suppressed so enabling documentation does not introduce warnings for
undocumented members.
(feat): Added a package-metadata config block for NuGet metadata written into the
generated csproj: description, authors, tags, copyright, icon,
project-url, repository-url, repository-type, include-source-link
(adds Microsoft.SourceLink.GitHub) and include-symbols (produces a
.snupkg).
2.82.1
(fix): Global headers typed as a literal<"..."> with an env fallback no longer throw when
neither the constructor parameter nor the environment variable is set. The literal is
known at compile time, so it is now used as the header’s default value.
(fix): The generated X-Fern-SDK-Version header value is now emitted as a globally qualified
reference, so it can no longer be shadowed by a constructor parameter or local that
PascalCases to Version (previously error CS1061: 'string' does not contain a definition for 'Current').
2.82.0
(fix): With respect-optional-request-body enabled, examples that omit an optional request body are no
longer dropped from the generated snippets and reference.
(feat): Add a respect-optional-request-body option. When enabled, an endpoint whose request body the API
does not require takes that body as Body? request = null, so the caller can leave the argument out
and the request is sent with no body and no body content type. Examples that supply no body render
as client.BulkRefundAsync(). The option defaults to false, so existing signatures and snippets are
unchanged.
2.81.1
(fix): Percent-encode ; in query parameter names and values. RFC 3986 permits it, but it
remains a legacy parameter separator for many servers, which truncated values such as
?mail2=a@example.com;%20b@example.com at the first ;.
2.81.0
(feat): Add an opt-in prefer-explicit-auth configuration option. When enabled (and the API composes
OAuth client-credentials with basic auth via auth: any), auth credentials passed
explicitly to the client constructor take precedence over environment-variable
defaults when selecting the auth scheme — e.g. explicitly provided basic auth
credentials win over OAuth client ID/secret environment variables. Disabled by
default, so existing generated output and runtime behavior are unchanged.
2.80.1
(fix): Fix generated mock server tests for examples that omit an optional request body. The
stub no longer matches on a Content-Type header that the bodyless request does not send.
2.80.0
(feat): Add opt-in allow-user-agent-app-info config. When enabled, generated clients expose an
optional AppInfo client option (Name, Version?, Comment?) whose sanitized product
token is appended to whatever User-Agent the SDK would otherwise send
({sdk}/{version} ... {product}/{product-version} ({comment})), following RFC 9110.
Disabled by default, so existing generated output is byte-identical, and it composes with
include-platform-headers, the configured user-agent template value, and the
user-agent-name-from-package fallback. Caller-supplied values are trimmed and encoded
(name/version percent-encoded to RFC 7230 tchar; comment delimiters (, ), \ and
control characters incl. CR/LF escaped), so untrusted values cannot inject header content.
Still overridable by an explicit User-Agent header and suppressed by omit-fern-headers.
Works in both unified and non-unified client-options modes; generated code compiles for
net462, net8.0, and netstandard2.0.
2.79.4
(fix): Respect the user-agent config template when include-platform-headers is enabled. The
structured User-Agent previously always used the NuGet package id, ignoring the
configured template.
2.79.3
(fix): Only reference README.md in the generated .csproj when the file actually exists. The
<PackageReadmeFile> property and the packed <None Include> item are now guarded with an
MSBuild Exists condition, so dotnet pack no longer fails with NU5019 for outputs that do
not include a README (e.g. local-file-system output).
2.79.2
(fix): SDKs generated to local-file-system output now stamp the package name and version
from the IR’s nuget filesystem publish target (populated by the Fern CLI when
--version is passed) into Version.cs, the .csproj <Version> property, and the
structured User-Agent header. Previously local-file-system output always produced
Version.Current = "0.0.0" and used the root namespace as the User-Agent identity.
2.79.1
(fix): Global headers now honor their client-default value. The constructor
initializes the header from the explicit argument, then the environment
variable, then the client default. Previously the client default was only
applied on the header-dictionary path and was dropped entirely under
any-composed multi-scheme auth and endpoint-level security.
2.79.0
(feat): Add support for per-endpoint auth routing. When the API-level auth requirement is
ENDPOINT_SECURITY, each endpoint now applies only the auth scheme(s) it declares in
its IR security field (OR across the list of requirements, AND within a requirement,
and no auth when security is empty), instead of applying every configured credential
to every request. Behavior for the ALL and ANY auth requirements (the common cases)
is unchanged.
2.78.0
(feat): Support webhook body-hash binding in the generated WebhooksHelper.VerifySignature
helper. When a webhook’s HMAC signature configuration declares a bodyHashBinding
(as used by providers such as Twilio for JSON bodies), verification now first
recomputes an unkeyed hash of the raw request body and compares it, in constant time,
against the hash carried in the notification URL’s query parameter, failing closed on
a missing or mismatched value before performing the existing HMAC check over the
verbatim notification URL. The body-hash algorithm and encoding are independent of the
outer HMAC’s. Output is unchanged when no bodyHashBinding is configured.
2.76.6
(fix): Fix a thread-safety bug in the generated OAuthTokenProvider. The token
cache is now guarded by a SemaphoreSlim with double-checked locking (the
same pattern already used by InferredAuthTokenProvider), so only one
caller refreshes the token under concurrent load and cached values are
published safely. The cache-hit path stays lock-free.
2.76.5
(fix): When a client is constructed with both a named environment and server URL
variables (e.g. Region), the generated client now renders the selected
environment’s URL template(s) instead of always using the first (default)
environment’s template. Explicitly provided custom base URLs and custom
environment values are never overridden.
2.76.4
(fix): Global API headers configured with an env fallback (e.g. X-Twilio-Version with
env: TWILIO_VERSION) now fall back to the environment variable in the root client
constructor when the parameter is not passed explicitly. Optional headers never throw
when both the parameter and the environment variable are missing.
2.77.0
(feat): Add a server-url-variables configuration flag (default true) that controls whether server
URL variables declared on the API’s environments are exposed as client options and
interpolated into the environment URL template(s) at construction time. When set to false,
those client options and the URL-template interpolation are suppressed and the generated SDK
falls back to the base-URL behavior from before the feature. Defaults to true, so existing
generated output is unchanged.
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.