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): 将捆绑的 @fern-api/generator-cli 升级到 0.9.44,以便在推送到 GitHub 时对每个仅存在于本地的提交都进行签名,而不仅仅是 HEAD。Replay 分支包含多个提交(例如 [fern-generated] + [fern-replay]);此前只有 HEAD 提交通过 GitHub API 重新创建并签名,导致 PR 上更早的提交未经验证。

2.72.0

(feat): 为 C# SDK 生成器新增 default-timeout-in-milliseconds 配置选项,用于以毫秒表示默认网络超时(映射到 .NET 的 TimeSpan)。生成的 ClientOptions.Timeout 现在根据毫秒计算(当设置为 "infinity" 时为 Timeout.InfiniteTimeSpan)。default-timeout-in-seconds 选项现已弃用,但仍完全向后兼容:当仅设置秒键时,会将其转换为毫秒。当二者同时设置时,新键优先。

2.71.2

(fix): 修复当用户编写的示例以不同于 URL 路径模板的顺序列出路径参数时,mock-server 测试和 XML 文档 <example> 代码片段以错误顺序(CS1503)调用带路径参数的客户端方法的问题。生成的方法签名遵循 IR 的规范(URL 模板)顺序,但代码片段写入器此前按作者声明的顺序依位置消费示例的路径参数。现在示例值会按名称绑定到各个参数,并按端点规范的路径参数顺序输出,与生成的签名一致。

2.71.1

(fix): 修复 SSE 流重连正确性以匹配参考实现: (1) 未配置终止符时不重连(客户端无法区分已完成的流和断开的连接)。 (2) 当服务器未发送 retry: 指令时,重连尝试之间应用默认 1 秒退避(之前为零延迟)。 (3) 使用最后一个已分发的事件 ID 进行重连,而非最后一个已解析的 id,防止在事件中途断开时静默丢失事件。 (4) 将重连函数失败视为已消耗的尝试;当上限用尽时抛出 IOException 并将最后一次失败作为 InnerException,而非静默截断流。 (5) 让 OperationCanceledException 从 reconnectFn 立即传播,而非将其作为重试尝试吞没。 (6) 仅在成功获取新响应后才释放旧 HTTP 响应,防止重试时出现 ObjectDisposedException。

2.70.0

(feat): 添加对未记录/额外参数的支持:来自 RequestOptions 的 AdditionalQueryParameters 现在应用于所有端点(之前只有定义了查询参数的端点才会合并它们)。 还为 README 生成添加了 ADDITIONAL_BODY_PROPERTIES 功能。

2.69.2

(fix): 通过将 API 密钥通过 env 块传递而非直接插值来修复 OIDC 发布工作流中的 shell 注入代码扫描警报。

2.69.1

(fix): 修复当头部、查询参数或认证头部示例值包含 C# 字符串字面量中的特殊字符(例如双引号、反斜杠或控制字符)时, 生成的线路测试无法编译的问题。这些值现在通过 mock-server .WithHeader(...)/.WithParam(...) 匹配器中的 escapeForCSharpString 发出,而不是直接插入到双引号字符串中。

2.69.0

(feat): 添加 NuGet Trusted Publishing(OIDC)支持作为配置门控的发布策略。 在 generators.yml 中设置 api-key: OIDC 以生成使用 NuGet/login 进行短期 OIDC 令牌 而非长期 API 密钥的 GitHub Actions 工作流。