diff --git a/generators/csharp/base/src/asIs/Extensions.cs b/generators/csharp/base/src/asIs/Extensions.cs
index c94625b493f4..d6724096284f 100644
--- a/generators/csharp/base/src/asIs/Extensions.cs
+++ b/generators/csharp/base/src/asIs/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/generators/csharp/base/src/asIs/NullableAttribute.Template.cs b/generators/csharp/base/src/asIs/NullableAttribute.Template.cs
index 35ecafbc5793..4afc7b88c51d 100644
--- a/generators/csharp/base/src/asIs/NullableAttribute.Template.cs
+++ b/generators/csharp/base/src/asIs/NullableAttribute.Template.cs
@@ -2,7 +2,7 @@ namespace <%= namespace%>;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace <%= namespace%>;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute
diff --git a/generators/csharp/base/src/asIs/Optional.Template.cs b/generators/csharp/base/src/asIs/Optional.Template.cs
index 02ad860743aa..db7c56cae462 100644
--- a/generators/csharp/base/src/asIs/Optional.Template.cs
+++ b/generators/csharp/base/src/asIs/Optional.Template.cs
@@ -267,7 +267,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -345,7 +345,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -400,7 +400,7 @@ string key
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -425,7 +425,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs b/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs
index 9742cde0d509..ab5ca0780c05 100644
--- a/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs
+++ b/generators/csharp/base/src/asIs/OptionalAttribute.Template.cs
@@ -2,16 +2,16 @@ namespace <%= namespace%>;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute
diff --git a/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs b/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs
index 1138359bf1ec..46672015ca6a 100644
--- a/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs
+++ b/generators/csharp/base/src/asIs/QueryStringBuilder.Template.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs b/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs
index b0455e690ded..2321f1c2be75 100644
--- a/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs
+++ b/generators/csharp/base/src/asIs/WebSockets/Query.Template.cs
@@ -122,7 +122,7 @@ public void Add(string key, Object? value)
///
/// Converts the query parameters to a URL-encoded query string.
///
- /// A string representation of the query parameters in the format "key1=value1&key2=value2".
+ /// A string representation of the query parameters in the format "key1=value1&key2=value2".
public override string ToString()
{
return string.Join(
diff --git a/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs b/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs
index 82206fc653f3..f7fc8582943d 100644
--- a/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs
+++ b/generators/csharp/base/src/asIs/WebSockets/WebSocketClient.Template.cs
@@ -134,6 +134,7 @@ private void EnsureConnected()
/// Sends a text message instantly through the WebSocket connection.
///
/// The text message to send.
+ /// Token to cancel the send operation.
/// A task representing the asynchronous send operation.
/// Thrown when the connection is not in Connected status.
public global::System.Threading.Tasks.Task SendInstant(string message, CancellationToken cancellationToken = default)
@@ -146,6 +147,7 @@ private void EnsureConnected()
/// Sends a binary message instantly through the WebSocket connection.
///
/// The binary message to send as a Memory<byte>.
+ /// Token to cancel the send operation.
/// A task representing the asynchronous send operation.
/// Thrown when the connection is not in Connected status.
public global::System.Threading.Tasks.Task SendInstant(Memory message, CancellationToken cancellationToken = default)
@@ -158,6 +160,7 @@ private void EnsureConnected()
/// Sends a binary message instantly through the WebSocket connection.
///
/// The binary message to send as an ArraySegment<byte>.
+ /// Token to cancel the send operation.
/// A task representing the asynchronous send operation.
/// Thrown when the connection is not in Connected status.
public global::System.Threading.Tasks.Task SendInstant(ArraySegment message, CancellationToken cancellationToken = default)
@@ -170,6 +173,7 @@ private void EnsureConnected()
/// Sends a binary message instantly through the WebSocket connection.
///
/// The binary message to send as a byte array.
+ /// Token to cancel the send operation.
/// A task representing the asynchronous send operation.
/// Thrown when the connection is not in Connected status.
public global::System.Threading.Tasks.Task SendInstant(byte[] message, CancellationToken cancellationToken = default)
diff --git a/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs b/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs
index 5cc26a39e527..f29f9af2b6c4 100644
--- a/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs
+++ b/generators/csharp/base/src/asIs/test/Utils/OptionalComparer.Template.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/generators/csharp/base/src/project/CsharpProject.ts b/generators/csharp/base/src/project/CsharpProject.ts
index 44ecaeff64f0..2de47de09127 100644
--- a/generators/csharp/base/src/project/CsharpProject.ts
+++ b/generators/csharp/base/src/project/CsharpProject.ts
@@ -10,6 +10,7 @@ import { AsIsFiles } from "../AsIs.js";
import { GeneratorContext } from "../context/GeneratorContext.js";
import { findDotnetToolPath } from "../findDotNetToolPath.js";
import { CSharpFile } from "./CSharpFile.js";
+import { TARGET_FRAMEWORKS } from "./targetFrameworks.js";
const eta = new Eta({ autoEscape: false, useWith: true, autoTrim: false });
@@ -822,6 +823,21 @@ function generateDeterministicGuid(name: string): string {
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`.toUpperCase();
}
+/**
+ * Joins a metadata value that may be a single string or a list into the
+ * delimiter-separated form MSBuild expects. Returns undefined when unset.
+ */
+function joinMetadataList(value: string | string[] | undefined, delimiter: string): string | undefined {
+ if (value == null) {
+ return undefined;
+ }
+ return Array.isArray(value) ? value.join(delimiter) : value;
+}
+
+function escapeXml(value: string): string {
+ return value.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
+}
+
declare namespace CsProj {
interface Args {
name: string;
@@ -969,6 +985,13 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)}
''
);
}
+ if (this.generation.settings.packageMetadata["include-source-link"]) {
+ pushIfNotOverridden(
+ result,
+ SOURCE_LINK_PACKAGE.name,
+ ``
+ );
+ }
for (const [name, version] of Object.entries(extraDeps)) {
// PolySharp is already handled above with its required metadata.
if (name.toLowerCase() === "polysharp") {
@@ -1084,7 +1107,7 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)}
);
}
result.push(
- `${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}net462;net8.0;net9.0;netstandard2.0`
+ `${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}${TARGET_FRAMEWORKS.join(";")}`
);
result.push(
`${this.generation.constants.formatting.indent}${this.generation.constants.formatting.indent}enable`
@@ -1131,15 +1154,81 @@ ${this.getAdditionalItemGroups().join(`\n${indent}`)}
);
}
- if (this.githubUrl != null) {
- result.push(`${this.githubUrl}`);
- }
+ result.push(...this.getPackageMetadataProperties());
+
result.push("true");
return result;
}
+ /**
+ * NuGet package metadata and XML documentation properties, sourced from the
+ * `package-metadata` and `generate-documentation-file` config options and
+ * falling back to values derived from the IR (e.g. the GitHub URL).
+ */
+ private getPackageMetadataProperties(): string[] {
+ const result: string[] = [];
+ const metadata = this.generation.settings.packageMetadata;
+
+ if (this.generation.settings.generateDocumentationFile) {
+ result.push("true");
+ // Publishing XML docs should not force every undocumented public
+ // member to emit CS1591.
+ result.push("$(NoWarn);CS1591");
+ }
+
+ if (metadata.description != null) {
+ result.push(`${escapeXml(metadata.description)}`);
+ }
+ const authors = joinMetadataList(metadata.authors, ",");
+ if (authors != null) {
+ result.push(`${escapeXml(authors)}`);
+ }
+ const tags = joinMetadataList(metadata.tags, ";");
+ if (tags != null) {
+ result.push(`${escapeXml(tags)}`);
+ }
+ if (metadata.copyright != null) {
+ result.push(`${escapeXml(metadata.copyright)}`);
+ }
+ if (metadata.icon != null) {
+ result.push(`${escapeXml(path.basename(metadata.icon))}`);
+ }
+
+ const projectUrl = metadata["project-url"] ?? this.githubUrl;
+ if (projectUrl != null) {
+ result.push(`${escapeXml(projectUrl)}`);
+ }
+ const repositoryUrl = metadata["repository-url"] ?? this.githubUrl;
+ if (repositoryUrl != null) {
+ result.push(`${escapeXml(repositoryUrl)}`);
+ result.push(`${escapeXml(metadata["repository-type"] ?? "git")}`);
+ }
+
+ if (metadata["include-symbols"]) {
+ result.push("true");
+ result.push("snupkg");
+ }
+ if (metadata["include-source-link"]) {
+ result.push("true");
+ result.push("true");
+ result.push("true");
+ }
+
+ return result;
+ }
+
private getAdditionalItemGroups(): string[] {
const result: string[] = [];
+ const icon = this.generation.settings.packageMetadata.icon;
+ if (icon != null) {
+ // The configured path is relative to the root of the generated output,
+ // matching how a custom license file is referenced below.
+ result.push(`
+
+
+
+`);
+ }
if (this.license != null && this.license.type === "custom") {
result.push(`
@@ -1195,3 +1284,12 @@ const PLATFORM_HEADERS_INBOX_PACKAGE = {
name: "System.Runtime.InteropServices.RuntimeInformation",
version: "4.3.0"
} as const;
+
+/**
+ * Enables SourceLink for GitHub-hosted repositories, so debuggers can step into
+ * the SDK sources. Only emitted when `package-metadata.include-source-link` is on.
+ */
+const SOURCE_LINK_PACKAGE = {
+ name: "Microsoft.SourceLink.GitHub",
+ version: "8.0.0"
+} as const;
diff --git a/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts b/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts
new file mode 100644
index 000000000000..0f7b0db08106
--- /dev/null
+++ b/generators/csharp/base/src/project/__test__/targetFrameworks.test.ts
@@ -0,0 +1,33 @@
+import { describe, expect, it } from "vitest";
+
+import { getTargetFrameworkRequirements, TARGET_FRAMEWORKS } from "../targetFrameworks.js";
+
+describe("getTargetFrameworkRequirements", () => {
+ it("renders the generated project's target frameworks", () => {
+ expect(getTargetFrameworkRequirements()).toEqual([
+ ".NET 8 and above",
+ ".NET Framework 4.6.2 and above",
+ ".NET Standard 2.0 and above"
+ ]);
+ });
+
+ it("collapses modern .NET versions into the lowest one", () => {
+ expect(getTargetFrameworkRequirements(["net9.0", "net10.0", "net8.0"])).toEqual([".NET 8 and above"]);
+ });
+
+ it("renders two-digit .NET Framework monikers", () => {
+ expect(getTargetFrameworkRequirements(["net48"])).toEqual([".NET Framework 4.8 and above"]);
+ });
+
+ it("ignores unrecognized monikers", () => {
+ expect(getTargetFrameworkRequirements(["net8.0-android", "nonsense"])).toEqual([]);
+ });
+
+ it("returns an empty list when there are no target frameworks", () => {
+ expect(getTargetFrameworkRequirements([])).toEqual([]);
+ });
+
+ it("keeps the csproj and requirements in sync", () => {
+ expect(TARGET_FRAMEWORKS.join(";")).toBe("net462;net8.0;net9.0;netstandard2.0");
+ });
+});
diff --git a/generators/csharp/base/src/project/index.ts b/generators/csharp/base/src/project/index.ts
index 30acd4190743..94d58ea05ba4 100644
--- a/generators/csharp/base/src/project/index.ts
+++ b/generators/csharp/base/src/project/index.ts
@@ -1,3 +1,4 @@
export { CSharpFile } from "./CSharpFile.js";
export { CsharpProject } from "./CsharpProject.js";
export * from "./PackageUtilities.js";
+export { getTargetFrameworkRequirements, TARGET_FRAMEWORKS } from "./targetFrameworks.js";
diff --git a/generators/csharp/base/src/project/targetFrameworks.ts b/generators/csharp/base/src/project/targetFrameworks.ts
new file mode 100644
index 000000000000..ed9104762025
--- /dev/null
+++ b/generators/csharp/base/src/project/targetFrameworks.ts
@@ -0,0 +1,50 @@
+/**
+ * The target frameworks every generated SDK project builds against.
+ */
+export const TARGET_FRAMEWORKS = ["net462", "net8.0", "net9.0", "netstandard2.0"] as const;
+
+const NET_FRAMEWORK_PATTERN = /^net(\d)(\d)(\d)?$/;
+const NET_STANDARD_PATTERN = /^netstandard(\d+)\.(\d+)$/;
+const NET_CORE_PATTERN = /^net(\d+)\.(\d+)$/;
+
+/**
+ * Renders the target frameworks as human-readable prerequisites for the README's
+ * requirements section, e.g. `net8.0` -> ".NET 8 and above".
+ *
+ * Consecutive modern .NET versions collapse into their lowest entry, since
+ * ".NET 8 and above" already covers `net9.0`.
+ */
+export function getTargetFrameworkRequirements(targetFrameworks: readonly string[] = TARGET_FRAMEWORKS): string[] {
+ const requirements: string[] = [];
+ let lowestNetCoreMajor: number | undefined;
+
+ for (const targetFramework of targetFrameworks) {
+ const netCore = NET_CORE_PATTERN.exec(targetFramework);
+ if (netCore?.[1] != null) {
+ const major = Number.parseInt(netCore[1], 10);
+ if (lowestNetCoreMajor == null || major < lowestNetCoreMajor) {
+ lowestNetCoreMajor = major;
+ }
+ continue;
+ }
+
+ const netStandard = NET_STANDARD_PATTERN.exec(targetFramework);
+ if (netStandard?.[1] != null && netStandard[2] != null) {
+ requirements.push(`.NET Standard ${netStandard[1]}.${netStandard[2]} and above`);
+ continue;
+ }
+
+ const netFramework = NET_FRAMEWORK_PATTERN.exec(targetFramework);
+ if (netFramework?.[1] != null && netFramework[2] != null) {
+ const version = [netFramework[1], netFramework[2], netFramework[3]]
+ .filter((part) => part != null)
+ .join(".");
+ requirements.push(`.NET Framework ${version} and above`);
+ }
+ }
+
+ if (lowestNetCoreMajor != null) {
+ requirements.unshift(`.NET ${lowestNetCoreMajor} and above`);
+ }
+ return requirements;
+}
diff --git a/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts b/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts
index 98489b6d4e30..cbea5d184a49 100644
--- a/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts
+++ b/generators/csharp/codegen/src/__test__/XmlDocWriter.test.ts
@@ -42,6 +42,49 @@ function escapeXmlDocContent(text: string): string {
return writer.toString();
}
+describe("XmlDocWriter.toCrefTarget", () => {
+ it("should keep a simple type name", () => {
+ expect(XmlDocWriter.toCrefTarget("string")).toBe("string");
+ expect(XmlDocWriter.toCrefTarget("MyClass")).toBe("MyClass");
+ });
+
+ it("should keep a namespace-qualified type name", () => {
+ expect(XmlDocWriter.toCrefTarget("System.Text.Json.Nodes.JsonNode")).toBe("System.Text.Json.Nodes.JsonNode");
+ });
+
+ it("should drop nullable annotations", () => {
+ expect(XmlDocWriter.toCrefTarget("object?")).toBe("object");
+ expect(XmlDocWriter.toCrefTarget("MyClass?")).toBe("MyClass");
+ });
+
+ it("should convert generics to brace syntax with framework type names", () => {
+ expect(XmlDocWriter.toCrefTarget("List")).toBe("List{String}");
+ expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBe("IEnumerable{Int32}");
+ expect(XmlDocWriter.toCrefTarget("Dictionary")).toBe("Dictionary{String, Object}");
+ });
+
+ it("should keep non-keyword generic arguments as written", () => {
+ expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBe("IEnumerable{MyClass}");
+ expect(XmlDocWriter.toCrefTarget("OneOf?")).toBe("OneOf{Foo, Bar}");
+ });
+
+ it("should reject nested generic arguments, which cannot be cref identifiers", () => {
+ expect(XmlDocWriter.toCrefTarget("IEnumerable>")).toBeUndefined();
+ expect(XmlDocWriter.toCrefTarget("Dictionary>")).toBeUndefined();
+ });
+
+ it("should reject arrays, which cannot be cref identifiers", () => {
+ expect(XmlDocWriter.toCrefTarget("byte[]")).toBeUndefined();
+ expect(XmlDocWriter.toCrefTarget("IEnumerable")).toBeUndefined();
+ });
+
+ it("should reject types that are not plain names", () => {
+ expect(XmlDocWriter.toCrefTarget("")).toBeUndefined();
+ expect(XmlDocWriter.toCrefTarget("(string, int)")).toBeUndefined();
+ expect(XmlDocWriter.toCrefTarget("global::MyNamespace.MyClass")).toBeUndefined();
+ });
+});
+
describe("XmlDocWriter.escapeXmlDocContent", () => {
describe("converts HTML tags to XMLDoc equivalents", () => {
it("should convert inline to ", () => {
@@ -213,6 +256,50 @@ describe("XmlDocWriter.escapeXmlDocContent", () => {
});
});
+ describe("escapes bare ampersands", () => {
+ it("should escape a standalone ampersand", () => {
+ const result = escapeXmlDocContent("- &: HTML entities");
+ expect(result).toBe("- &: HTML entities");
+ });
+
+ it("should escape ampersands in urls", () => {
+ const result = escapeXmlDocContent("/search?a=1&b=2");
+ expect(result).toBe("/search?a=1&b=2");
+ });
+
+ it("should not double-escape existing entities", () => {
+ const result = escapeXmlDocContent("& < >");
+ expect(result).toBe("& < >");
+ });
+
+ it("should escape ampersands alongside angle brackets", () => {
+ const result = escapeXmlDocContent("List & Dictionary");
+ expect(result).toBe("List<string> & Dictionary<string, int>");
+ });
+ });
+
+ describe("escapes attribute values", () => {
+ it("should escape ampersands in a converted link href", () => {
+ const result = escapeXmlDocContent('See here');
+ expect(result).toBe('See here');
+ });
+
+ it("should not double-escape entities already in a href", () => {
+ const result = escapeXmlDocContent('See here');
+ expect(result).toBe('See here');
+ });
+
+ it("should escape ampersands in preserved tag attributes", () => {
+ const result = escapeXmlDocContent('See here');
+ expect(result).toBe('See here');
+ });
+
+ it("should escape angle brackets and quotes in attribute values", () => {
+ const result = escapeXmlDocContent('');
+ expect(result).toBe('');
+ });
+ });
+
describe("handles mixed content", () => {
it("should handle comparison within sentence with converted link", () => {
const result = escapeXmlDocContent('When x < y, see docs');
diff --git a/generators/csharp/codegen/src/ast/core/Writer.ts b/generators/csharp/codegen/src/ast/core/Writer.ts
index 409eb3984ca3..ab85868293e2 100644
--- a/generators/csharp/codegen/src/ast/core/Writer.ts
+++ b/generators/csharp/codegen/src/ast/core/Writer.ts
@@ -1,4 +1,4 @@
-import { AbstractWriter } from "@fern-api/browser-compatible-base-generator";
+import { AbstractAstNode, AbstractWriter } from "@fern-api/browser-compatible-base-generator";
import { Generation } from "../../context/generation-info.js";
import { type ClassReference } from "../types/ClassReference.js";
@@ -85,6 +85,31 @@ export class Writer extends AbstractWriter {
this.typeScopeStack.pop();
}
+ /* Renders the node in isolation and returns the result instead of appending it to this
+ writer's buffer. References collected while rendering are forwarded to this writer so
+ that the imports the node depends on are still emitted. */
+ public renderNodeToString(node: AbstractAstNode): string {
+ const scratch = new Writer({
+ namespace: this.namespace,
+ allNamespaceSegments: this.allNamespaceSegments,
+ allTypeClassReferences: this.allTypeClassReferences,
+ generation: this.generation,
+ skipImports: this.skipImports,
+ skipGlobalQualifier: this.skipGlobalQualifier
+ });
+ for (const enclosingType of this.typeScopeStack) {
+ scratch.pushTypeScope(enclosingType);
+ }
+ scratch.writeNode(node);
+ for (const [namespace, references] of Object.entries(scratch.references)) {
+ this.addNamespace(namespace);
+ for (const reference of references) {
+ this.addReference(reference);
+ }
+ }
+ return scratch.toString(true);
+ }
+
public addNamespace(namespace: string): void {
const foundNamespace = this.references[namespace];
if (foundNamespace == null) {
diff --git a/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts b/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts
index ce6f0b71adaa..637da6a67e91 100644
--- a/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts
+++ b/generators/csharp/codegen/src/ast/core/XmlDocWriter.ts
@@ -73,6 +73,33 @@ export class XmlDocWriter {
"tbody"
]);
+ // Matches an ampersand that does not already begin a character or entity reference
+ private static readonly BARE_AMPERSAND_PATTERN = /&(?!(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);)/g;
+
+ // A (possibly namespace-qualified) type name, optionally followed by generic arguments
+ private static readonly TYPE_NAME_PATTERN = /^([A-Za-z_][A-Za-z0-9_.]*)(?:<(.+)>)?$/;
+ private static readonly IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_.]*$/;
+
+ // Generic arguments in a cref must be identifiers, so keyword aliases are replaced by the
+ // framework type they alias
+ private static readonly KEYWORD_ALIASES: Record = {
+ bool: "Boolean",
+ byte: "Byte",
+ char: "Char",
+ decimal: "Decimal",
+ double: "Double",
+ float: "Single",
+ int: "Int32",
+ long: "Int64",
+ object: "Object",
+ sbyte: "SByte",
+ short: "Int16",
+ string: "String",
+ uint: "UInt32",
+ ulong: "UInt64",
+ ushort: "UInt16"
+ };
+
private writer: Writer;
private wrotePrefixOnCurrentLine: boolean = false;
constructor(writer: Writer) {
@@ -137,6 +164,76 @@ export class XmlDocWriter {
this.writer.writeNode(node);
}
+ /**
+ * Writes a documentation reference to a type. Types that can be expressed as a
+ * documentation comment identifier are written as `` so that the
+ * compiler resolves them and IDEs link them; anything else falls back to inline code.
+ */
+ public writeSeeType(type: AstNode): void {
+ const rendered = this.writer.renderNodeToString(type);
+ const crefTarget = XmlDocWriter.toCrefTarget(rendered);
+ if (crefTarget != null) {
+ this.write(``);
+ return;
+ }
+ this.write(`${this.escapeXmlDocContent(rendered)}`);
+ }
+
+ /**
+ * Converts C# source syntax for a type into a documentation comment identifier, or returns
+ * undefined when the type cannot be expressed as one.
+ *
+ * Nullable annotations are dropped (`object?` -> `object`) because they are not part of a
+ * type's identifier, and generic arguments use brace syntax (`List` -> `List{Foo}`)
+ * because crefs are resolved by the compiler rather than rendered as text. Generic arguments
+ * must be identifiers, so keyword aliases become framework type names
+ * (`List` -> `List{String}`) and arrays or nested generic arguments are rejected.
+ */
+ public static toCrefTarget(renderedType: string): string | undefined {
+ const type = renderedType.trim().replaceAll("?", "");
+ const match = XmlDocWriter.TYPE_NAME_PATTERN.exec(type);
+ if (match == null) {
+ return undefined;
+ }
+ const [, name, genericArguments] = match;
+ if (name == null) {
+ return undefined;
+ }
+ if (genericArguments == null) {
+ return name;
+ }
+ const crefArguments: string[] = [];
+ for (const argument of XmlDocWriter.splitGenericArguments(genericArguments)) {
+ const identifier = XmlDocWriter.KEYWORD_ALIASES[argument] ?? argument;
+ if (!XmlDocWriter.IDENTIFIER_PATTERN.test(identifier)) {
+ return undefined;
+ }
+ crefArguments.push(identifier);
+ }
+ return crefArguments.length === 0 ? undefined : `${name}{${crefArguments.join(", ")}}`;
+ }
+
+ private static splitGenericArguments(genericArguments: string): string[] {
+ const arguments_: string[] = [];
+ let depth = 0;
+ let current = "";
+ for (const character of genericArguments) {
+ if (character === "," && depth === 0) {
+ arguments_.push(current.trim());
+ current = "";
+ continue;
+ }
+ if (character === "<") {
+ depth++;
+ } else if (character === ">") {
+ depth--;
+ }
+ current += character;
+ }
+ arguments_.push(current.trim());
+ return arguments_;
+ }
+
public writeXmlNode(nodeName: string, text: string): void {
this.writePrefix();
this.writeOpenXmlNode(nodeName);
@@ -198,7 +295,10 @@ export class XmlDocWriter {
}
return match;
});
- const escaped = withPlaceholders.replaceAll("<", "<").replaceAll(">", ">");
+ const escaped = withPlaceholders
+ .replace(XmlDocWriter.BARE_AMPERSAND_PATTERN, "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">");
return escaped.replace(/\uE000(\d+)\uE000/g, (_, index: string) => tags[parseInt(index, 10)] ?? "");
}
@@ -283,7 +383,7 @@ export class XmlDocWriter {
case "a": {
const href = el.attribs.href;
if (href) {
- return `${children}`;
+ return `${children}`;
}
return children;
}
@@ -316,7 +416,7 @@ export class XmlDocWriter {
// Known XMLDoc tags: pass through with attributes
if (XmlDocWriter.SAFE_XML_DOC_TAGS.has(tag)) {
const attrs = Object.entries(el.attribs)
- .map(([k, v]) => ` ${k}="${v}"`)
+ .map(([k, v]) => ` ${k}="${XmlDocWriter.escapeXmlAttributeValue(v)}"`)
.join("");
if (el.children.length === 0) {
return `<${el.name}${attrs}/>`;
@@ -329,6 +429,19 @@ export class XmlDocWriter {
}
}
+ /**
+ * Escapes the markup characters that are not allowed raw inside an XML attribute value.
+ * Ampersands that already begin a character or entity reference are left alone so that
+ * values such as `?a=1&b=2` are not double escaped.
+ */
+ private static escapeXmlAttributeValue(value: string): string {
+ return value
+ .replace(XmlDocWriter.BARE_AMPERSAND_PATTERN, "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """);
+ }
+
private decodeHtmlEntities(text: string): string {
const entityMap: Record = {
"+": "+",
diff --git a/generators/csharp/codegen/src/context/generation-info.ts b/generators/csharp/codegen/src/context/generation-info.ts
index e1e3eef4dc95..67a7712b051f 100644
--- a/generators/csharp/codegen/src/context/generation-info.ts
+++ b/generators/csharp/codegen/src/context/generation-info.ts
@@ -209,6 +209,10 @@ export class Generation {
rootNamespaceForCoreClasses: () => this.customConfig["root-namespace-for-core-classes"] ?? true,
/** Custom NuGet package identifier. Default: "" (uses root namespace). */
packageId: () => this.customConfig["package-id"] ?? "",
+ /** When true, the generated csproj emits XML documentation so the nupkg ships `.xml`. Default: true. */
+ generateDocumentationFile: () => this.customConfig["generate-documentation-file"] ?? true,
+ /** NuGet package metadata (description, authors, tags, icon, urls, SourceLink, symbols) for the generated csproj. Default: {}. */
+ packageMetadata: () => this.customConfig["package-metadata"] ?? {},
/** When true, generates enums that can handle unknown/future values gracefully. Default: true. */
isForwardCompatibleEnumsEnabled: () =>
this.customConfig["enable-forward-compatible-enums"] ??
diff --git a/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts b/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts
index 592190975370..2c01a21a4f47 100644
--- a/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts
+++ b/generators/csharp/codegen/src/custom-config/CsharpConfigSchema.ts
@@ -27,6 +27,42 @@ export const OutputPathSchema = z.union([
export type OutputPathSchema = z.infer;
+/**
+ * Schema for NuGet package metadata written into the generated csproj.
+ *
+ * Every field is optional; unset fields are omitted from the csproj so NuGet
+ * falls back to its own defaults (or to values already derived from the IR,
+ * such as the license and the GitHub project URL).
+ */
+export const PackageMetadataSchema = z.object({
+ /** `` — the package description shown on nuget.org. */
+ description: z.string().optional(),
+ /** `` — a single author or a list of authors. */
+ authors: z.union([z.string(), z.array(z.string())]).optional(),
+ /** `` — search tags, either space-separated or a list. */
+ tags: z.union([z.string(), z.array(z.string())]).optional(),
+ /** ``. */
+ copyright: z.string().optional(),
+ /**
+ * `` — path to an image, relative to the project directory,
+ * that is packed into the nupkg. The file itself must be present in the
+ * output (e.g. committed and listed in `.fernignore`).
+ */
+ icon: z.string().optional(),
+ /** `` — overrides the URL derived from the GitHub output location. */
+ "project-url": z.string().optional(),
+ /** `` — defaults to the GitHub output location when unset. */
+ "repository-url": z.string().optional(),
+ /** ``. Default: "git" when a repository URL is present. */
+ "repository-type": z.string().optional(),
+ /** When true, adds Microsoft.SourceLink.GitHub and enables deterministic, source-linked builds. Default: false. */
+ "include-source-link": z.boolean().optional(),
+ /** When true, produces a `.snupkg` symbol package alongside the `.nupkg`. Default: false. */
+ "include-symbols": z.boolean().optional()
+});
+
+export type PackageMetadataSchema = z.infer;
+
export const CsharpConfigSchema = z.object({
// Influence dynamic snippets.
namespace: z.string().optional(),
@@ -98,6 +134,13 @@ export const CsharpConfigSchema = z.object({
"enable-forward-compatible-enums": z.boolean().optional(),
"generate-error-types": z.boolean().optional(),
"package-id": z.string().optional(),
+ // When true, the generated csproj sets , so the
+ // published nupkg ships `lib//.xml` and consumers get
+ // IntelliSense. CS1591 (missing XML comment for a public member) is
+ // suppressed so enabling docs does not add warnings for undocumented types.
+ "generate-documentation-file": z.boolean().optional(),
+ // NuGet package metadata written into the generated csproj.
+ "package-metadata": PackageMetadataSchema.optional(),
"generate-mock-server-tests": z.boolean().optional(),
"enable-wire-tests": z.boolean().optional(),
"include-exception-handler": z.boolean().optional(),
diff --git a/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts b/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts
index 800a74ea479a..8580fb288b87 100644
--- a/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts
+++ b/generators/csharp/model/src/undiscriminated-union/UndiscriminatedUnionGenerator.ts
@@ -219,8 +219,8 @@ export class UndiscriminatedUnionGenerator extends FileGenerator {
- writer.write(`Factory method to create a union from a `);
- writer.writeNode(member.csharpType);
+ writer.write("Factory method to create a union from a ");
+ writer.writeSeeType(member.csharpType);
writer.write(" value.");
}
},
@@ -293,10 +293,10 @@ export class UndiscriminatedUnionGenerator extends FileGenerator {
- writer.write(`Returns the value as a if is '${escapeForCSharpString(member.discriminator)}', otherwise throws an exception.`
+ ` if is '${escapeForCSharpString(member.discriminator)}', otherwise throws an exception.`
);
},
exceptions: new Map([
@@ -364,9 +364,9 @@ export class UndiscriminatedUnionGenerator extends FileGenerator {
- writer.write(`Attempts to cast the value to a and returns true if successful.`);
+ writer.write("Attempts to cast the value to a ");
+ writer.writeSeeType(member.csharpType);
+ writer.write(" and returns true if successful.");
}
},
access: ast.Access.Public,
diff --git a/generators/csharp/model/src/union/UnionGenerator.ts b/generators/csharp/model/src/union/UnionGenerator.ts
index fd8bb2d59fff..2ba68e9292d0 100644
--- a/generators/csharp/model/src/union/UnionGenerator.ts
+++ b/generators/csharp/model/src/union/UnionGenerator.ts
@@ -155,9 +155,9 @@ export class UnionGenerator extends FileGenerator {
- writer.write(`Create an instance of ${this.classReference.name} with .');
+ writer.write(`Create an instance of ${this.classReference.name} with `);
+ writer.writeSeeType(innerClassType);
+ writer.write(".");
}
},
access: ast.Access.Public,
@@ -200,10 +200,10 @@ export class UnionGenerator extends FileGenerator {
- writer.write('Returns the value as a if is '${escapeForCSharpString(getWireValue(type.discriminantValue))}', otherwise throws an exception.`
+ ` if is '${escapeForCSharpString(getWireValue(type.discriminantValue))}', otherwise throws an exception.`
);
},
exceptions: new Map([
@@ -334,9 +334,9 @@ export class UnionGenerator extends FileGenerator {
- writer.write('Attempts to cast the value to a and returns true if successful.');
+ writer.write("Attempts to cast the value to a ");
+ writer.writeSeeType(memberType);
+ writer.write(" and returns true if successful.");
}
},
access: ast.Access.Public,
diff --git a/generators/csharp/sdk/changes/2.83.0/feat-docs-and-package-metadata.yml b/generators/csharp/sdk/changes/2.83.0/feat-docs-and-package-metadata.yml
new file mode 100644
index 000000000000..d76746579f92
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/feat-docs-and-package-metadata.yml
@@ -0,0 +1,17 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ Added a `generate-documentation-file` config option (default `true`) so the
+ generated csproj emits XML documentation and the published NuGet package ships
+ `lib//.xml`, giving consumers IntelliSense. CS1591 is
+ suppressed so enabling documentation does not introduce warnings for
+ undocumented members.
+ type: feat
+
+- summary: |
+ 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`).
+ type: feat
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-client-options-global-headers.yml b/generators/csharp/sdk/changes/2.83.0/fix-client-options-global-headers.yml
new file mode 100644
index 000000000000..be2c2ad867b8
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-client-options-global-headers.yml
@@ -0,0 +1,16 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ Global header values set on `ClientOptions` are now respected in the default
+ (non-unified) client shape. Previously the generated root client read only the
+ constructor parameter for a promoted global header, so
+ `new Client(clientOptions: new ClientOptions { Version = "..." })` was silently
+ ignored and a stray environment variable could win instead. The resolution
+ order is now: explicit constructor argument, `ClientOptions` property,
+ environment variable, then the literal/client default.
+ type: fix
+
+- summary: |
+ `ClientOptions.Clone()` now copies literal global header properties (e.g.
+ `Version`), which were previously dropped when the options were cloned.
+ type: fix
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-doc-comment-attribute-escaping.yml b/generators/csharp/sdk/changes/2.83.0/fix-doc-comment-attribute-escaping.yml
new file mode 100644
index 000000000000..40359f6ae66a
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-doc-comment-attribute-escaping.yml
@@ -0,0 +1,6 @@
+- summary: |
+ Escape markup characters in the attribute values of documentation comment tags. Descriptions
+ containing links such as `` no longer emit invalid
+ XML (CS1570) in generated documentation comments, while attribute values that already contain
+ character or entity references are left untouched.
+ type: fix
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-readme-requirements.yml b/generators/csharp/sdk/changes/2.83.0/fix-readme-requirements.yml
new file mode 100644
index 000000000000..2b302891df6d
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-readme-requirements.yml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ The generated README's `## Requirements` section is now populated with the
+ project's target frameworks (".NET 8 and above", ".NET Framework 4.6.2 and
+ above", ".NET Standard 2.0 and above"). Previously the C# generator passed an
+ empty requirements list, so the section rendered as a dangling
+ "This SDK requires:" with no entries.
+ type: fix
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-readme-snippets.yml b/generators/csharp/sdk/changes/2.83.0/fix-readme-snippets.yml
new file mode 100644
index 000000000000..6d510f5dbdf3
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-readme-snippets.yml
@@ -0,0 +1,14 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ README and dynamic snippets no longer pass an upper-cased placeholder for
+ global header constructor parameters (e.g. `new Client("TOKEN", "VERSION")`,
+ which sent the literal header value `VERSION` at runtime). Snippets now use
+ the header's literal or client default value when one is known.
+ type: fix
+
+- summary: |
+ Fixed invalid C# in the generated README: `RequestOptions` examples used
+ object-initializer syntax with `:` instead of `=` (`new RequestOptions { MaxRetries: 0 }`),
+ and the `WithRawResponse` section declared `var data` twice in one block.
+ type: fix
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-union-cref-doc-comments.yml b/generators/csharp/sdk/changes/2.83.0/fix-union-cref-doc-comments.yml
new file mode 100644
index 000000000000..f6dd9c67b5fb
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-union-cref-doc-comments.yml
@@ -0,0 +1,8 @@
+- summary: |
+ Fix invalid `` documentation comments generated for union types. Type names
+ are now converted to documentation comment identifiers (`List` becomes
+ `List{String}`, `object?` becomes `object`), and types that cannot be expressed as an
+ identifier (arrays, nested generic arguments) are rendered as escaped inline code instead.
+ This removes CS1570/CS1584/CS1658 warnings from generated SDKs that contain unions when XML
+ documentation is enabled.
+ type: fix
diff --git a/generators/csharp/sdk/changes/2.83.0/fix-xml-doc-comments.yml b/generators/csharp/sdk/changes/2.83.0/fix-xml-doc-comments.yml
new file mode 100644
index 000000000000..5bb1a921fd53
--- /dev/null
+++ b/generators/csharp/sdk/changes/2.83.0/fix-xml-doc-comments.yml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ Escaped generic type syntax in the XML doc comments of the generated core
+ files (`Optional`, `OptionalAttribute`, `NullableAttribute`, `Extensions`),
+ and added the missing `param` tags on `Extensions.Assert`. Building generated
+ SDKs with XML documentation enabled no longer emits CS1570/CS1573 warnings.
+ type: fix
diff --git a/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts b/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts
index 30ffefdf9cdd..4891ddfc3524 100644
--- a/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts
+++ b/generators/csharp/sdk/src/options/BaseOptionsGenerator.ts
@@ -179,11 +179,11 @@ export class BaseOptionsGenerator extends WithGeneration {
header: HttpHeader;
options: OptionArgs;
}
- ) {
+ ): ast.Field | undefined {
if (header.valueType.type !== "container" || header.valueType.container.type !== "literal") {
- return;
+ return undefined;
}
- classOrInterface.addField({
+ return classOrInterface.addField({
access: ast.Access.Public,
origin: header,
get: true,
@@ -251,13 +251,19 @@ export class BaseOptionsGenerator extends WithGeneration {
this.getBodyPropertiesField(iface, optionArgs);
}
- public getLiteralHeaderOptions(classOrInterface: ast.Interface | ast.Class, optionArgs: OptionArgs) {
+ /** Adds a client option for every literal-typed global header, and returns the added fields. */
+ public getLiteralHeaderOptions(classOrInterface: ast.Interface | ast.Class, optionArgs: OptionArgs): ast.Field[] {
+ const fields: ast.Field[] = [];
for (const header of this.context.ir.headers) {
- this.maybeGetLiteralHeaderField(classOrInterface, {
+ const field = this.maybeGetLiteralHeaderField(classOrInterface, {
header,
options: optionArgs
});
+ if (field != null) {
+ fields.push(field);
+ }
}
+ return fields;
}
private getLiteralRootClientParameterType({ literal }: { literal: Literal }): ast.Type {
diff --git a/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts b/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts
index b46f2f704896..2990fc434f0b 100644
--- a/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts
+++ b/generators/csharp/sdk/src/options/ClientOptionsGenerator.ts
@@ -35,6 +35,8 @@ export class ClientOptionsGenerator extends FileGenerator `\n ${field.name} = ${field.name},`)
.join("");
+ const literalHeaderFieldLines = this.literalHeaderFields
+ .map((field) => `\n ${field.name} = ${field.name},`)
+ .join("");
writer.writeStatement(
`return new ClientOptions
{${this.baseUrlField ? `\n ${this.baseUrlField.name} = ${this.baseUrlField.name},` : ""}${this.environmentField ? `\n ${this.environmentField.name} = ${this.environmentField.name},` : ""}${serverVariableFieldLines}
@@ -634,7 +639,7 @@ export class ClientOptionsGenerator extends FileGenerator(Headers)),
- AdditionalHeaders = AdditionalHeaders,${unifiedFieldLines}${this.appInfoField ? `\n ${this.appInfoField.name} = ${this.appInfoField.name},` : ""}
+ AdditionalHeaders = AdditionalHeaders,${literalHeaderFieldLines}${unifiedFieldLines}${this.appInfoField ? `\n ${this.appInfoField.name} = ${this.appInfoField.name},` : ""}
${this.settings.includeExceptionHandler ? "ExceptionHandler = ExceptionHandler.Clone()," : ""}
}`
);
@@ -705,6 +710,9 @@ export class ClientOptionsGenerator extends FileGenerator(other.Headers))"
);
writer.writeLine("AdditionalHeaders = other.AdditionalHeaders;");
+ for (const field of this.literalHeaderFields) {
+ writer.writeLine(`${field.name} = other.${field.name};`);
+ }
for (const field of this.unifiedFields) {
writer.writeLine(`${field.name} = other.${field.name};`);
}
diff --git a/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts b/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts
index efbd2d2481fd..80d5685b5f87 100644
--- a/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts
+++ b/generators/csharp/sdk/src/readme/ReadmeConfigBuilder.ts
@@ -1,3 +1,4 @@
+import { getTargetFrameworkRequirements } from "@fern-api/csharp-base";
import { CsharpConfigSchema } from "@fern-api/csharp-codegen";
import { Logger } from "@fern-api/logger";
import { FernGeneratorCli } from "@fern-fern/generator-cli-sdk";
@@ -46,7 +47,7 @@ export class ReadmeConfigBuilder {
referenceMarkdownPath: "./reference.md",
customSections: getCustomSections(context),
features,
- requirements: []
+ requirements: getTargetFrameworkRequirements()
};
}
diff --git a/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts b/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts
index 24f3825e8560..2d0e3e77941f 100644
--- a/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts
+++ b/generators/csharp/sdk/src/readme/ReadmeSnippetBuilder.ts
@@ -157,7 +157,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
var response = await ${this.getMethodCall(retryEndpoint)}(
...,
new ${this.requestOptionsName} {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
`)
@@ -171,7 +171,7 @@ var response = await ${this.getMethodCall(retryEndpoint)}(
var response = await ${this.getMethodCall(timeoutEndpoint)}(
...,
new ${this.requestOptionsName} {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
`)
@@ -231,7 +231,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await ${this.getMethodCall(rawResponseEndpoint)}(...);
+var parsedData = await ${this.getMethodCall(rawResponseEndpoint)}(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/generators/csharp/sdk/src/root-client/RootClientGenerator.ts b/generators/csharp/sdk/src/root-client/RootClientGenerator.ts
index 787cfa6f3424..32a5695b5962 100644
--- a/generators/csharp/sdk/src/root-client/RootClientGenerator.ts
+++ b/generators/csharp/sdk/src/root-client/RootClientGenerator.ts
@@ -65,6 +65,12 @@ interface ConstructorParameter {
* Falls back to parameter name if not provided
*/
exampleValue?: string;
+ /**
+ * A rendered C# expression to use in examples, for parameters whose value is known at
+ * compile time (a `literal<"...">`-typed or `client-default`ed global header). Takes
+ * precedence over `exampleValue`, which is quoted as a string.
+ */
+ exampleExpression?: string;
/**
* The client default value from x-fern-default.
* When present, the parameter is optional and uses this value as fallback.
@@ -94,6 +100,18 @@ function getLiteralHeaderValue(param: ConstructorParameter): Literal | undefined
: undefined;
}
+/** Renders a literal as the C# expression for its value. */
+function renderLiteral(literal: Literal): string {
+ switch (literal.type) {
+ case "string":
+ return `"${escapeForCSharpString(literal.string)}"`;
+ case "boolean":
+ return literal.boolean ? "true" : "false";
+ default:
+ assertNever(literal);
+ }
+}
+
export class RootClientGenerator extends FileGenerator {
private rawClient: RawClient;
private serviceId: ServiceId | undefined;
@@ -551,6 +569,14 @@ export class RootClientGenerator extends FileGenerator/.xml`, giving consumers IntelliSense. CS1591 is
+ suppressed so enabling documentation does not introduce warnings for
+ undocumented members.
+ type: feat
+ - summary: |
+ 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`).
+ type: feat
+ - summary: |
+ Global header values set on `ClientOptions` are now respected in the default
+ (non-unified) client shape. Previously the generated root client read only the
+ constructor parameter for a promoted global header, so
+ `new Client(clientOptions: new ClientOptions { Version = "..." })` was silently
+ ignored and a stray environment variable could win instead. The resolution
+ order is now: explicit constructor argument, `ClientOptions` property,
+ environment variable, then the literal/client default.
+ type: fix
+ - summary: |
+ `ClientOptions.Clone()` now copies literal global header properties (e.g.
+ `Version`), which were previously dropped when the options were cloned.
+ type: fix
+ - summary: |
+ Escape markup characters in the attribute values of documentation comment tags. Descriptions
+ containing links such as `` no longer emit invalid
+ XML (CS1570) in generated documentation comments, while attribute values that already contain
+ character or entity references are left untouched.
+ type: fix
+ - summary: |
+ The generated README's `## Requirements` section is now populated with the
+ project's target frameworks (".NET 8 and above", ".NET Framework 4.6.2 and
+ above", ".NET Standard 2.0 and above"). Previously the C# generator passed an
+ empty requirements list, so the section rendered as a dangling
+ "This SDK requires:" with no entries.
+ type: fix
+ - summary: |
+ README and dynamic snippets no longer pass an upper-cased placeholder for
+ global header constructor parameters (e.g. `new Client("TOKEN", "VERSION")`,
+ which sent the literal header value `VERSION` at runtime). Snippets now use
+ the header's literal or client default value when one is known.
+ type: fix
+ - summary: |
+ Fixed invalid C# in the generated README: `RequestOptions` examples used
+ object-initializer syntax with `:` instead of `=` (`new RequestOptions { MaxRetries: 0 }`),
+ and the `WithRawResponse` section declared `var data` twice in one block.
+ type: fix
+ - summary: |
+ Fix invalid `` documentation comments generated for union types. Type names
+ are now converted to documentation comment identifiers (`List` becomes
+ `List{String}`, `object?` becomes `object`), and types that cannot be expressed as an
+ identifier (arrays, nested generic arguments) are rendered as escaped inline code instead.
+ This removes CS1570/CS1584/CS1658 warnings from generated SDKs that contain unions when XML
+ documentation is enabled.
+ type: fix
+ - summary: |
+ Escaped generic type syntax in the XML doc comments of the generated core
+ files (`Optional`, `OptionalAttribute`, `NullableAttribute`, `Extensions`),
+ and added the missing `param` tags on `Extensions.Assert`. Building generated
+ SDKs with XML documentation enabled no longer emits CS1570/CS1573 warnings.
+ type: fix
+ createdAt: "2026-08-20"
+ irVersion: 67
- version: 2.82.1
changelogEntry:
- summary: |
diff --git a/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts b/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts
index 6be0b59b6595..5e7936e9d055 100644
--- a/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts
+++ b/generators/go-v2/sdk/src/readme/ReadmeConfigBuilder.ts
@@ -22,6 +22,7 @@ export class ReadmeConfigBuilder {
endpointSnippets
});
const snippetsByFeatureId = readmeSnippetBuilder.buildReadmeSnippetsByFeatureId();
+ const addendumsByFeatureId = readmeSnippetBuilder.buildReadmeAddendumsByFeatureId();
const features: FernGeneratorCli.ReadmeFeature[] = [];
for (const feature of featureConfig.features) {
@@ -35,6 +36,7 @@ export class ReadmeConfigBuilder {
id: feature.id,
advanced: feature.advanced,
description: feature.description,
+ addendum: addendumsByFeatureId[feature.id] ?? feature.addendum,
snippets: snippetsForFeature,
snippetsAreOptional: false
});
diff --git a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts
index 95812f71424d..f2dbc9d84570 100644
--- a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts
+++ b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts
@@ -1,4 +1,5 @@
import { AbstractReadmeSnippetBuilder, GeneratorError } from "@fern-api/base-generator";
+import { assertNever } from "@fern-api/core-utils";
import { FernGeneratorCli } from "@fern-fern/generator-cli-sdk";
import { FernGeneratorExec } from "@fern-fern/generator-exec-sdk";
import { FernIr } from "@fern-fern/ir-sdk";
@@ -90,7 +91,8 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
? {
[FernGeneratorCli.StructuredFeatureId.Pagination]: {
renderer: this.renderPaginationSnippet.bind(this),
- predicate: (endpoint: EndpointWithFilepath) => endpoint.endpoint.pagination != null
+ predicate: (endpoint: EndpointWithFilepath) =>
+ this.context.isEnabledPaginationEndpoint(endpoint.endpoint)
}
}
: undefined)
@@ -109,6 +111,73 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
return snippetsByFeatureId;
}
+ public buildReadmeAddendumsByFeatureId(): Record {
+ const addendums: Record = {};
+ const environmentVariablesAddendum = this.buildEnvironmentVariablesAddendum();
+ if (environmentVariablesAddendum != null) {
+ addendums[FernGeneratorCli.StructuredFeatureId.RequestOptions] = environmentVariablesAddendum;
+ }
+ return addendums;
+ }
+
+ private buildEnvironmentVariablesAddendum(): string | undefined {
+ const environmentVariables = this.getAuthEnvironmentVariables();
+ if (environmentVariables.length === 0) {
+ return undefined;
+ }
+ const bulletedList = environmentVariables
+ .map((environmentVariable) => `- \`${environmentVariable}\``)
+ .join("\n");
+ return [
+ "",
+ "When credentials are not explicitly provided, the client reads them from the",
+ "following environment variables:",
+ "",
+ bulletedList
+ ].join("\n");
+ }
+
+ private getAuthEnvironmentVariables(): FernIr.EnvironmentVariable[] {
+ const environmentVariables: FernIr.EnvironmentVariable[] = [];
+ for (const scheme of this.context.ir.auth?.schemes ?? []) {
+ switch (scheme.type) {
+ case "bearer":
+ if (scheme.tokenEnvVar != null) {
+ environmentVariables.push(scheme.tokenEnvVar);
+ }
+ break;
+ case "header":
+ if (scheme.headerEnvVar != null) {
+ environmentVariables.push(scheme.headerEnvVar);
+ }
+ break;
+ case "basic":
+ if (scheme.usernameEnvVar != null) {
+ environmentVariables.push(scheme.usernameEnvVar);
+ }
+ if (scheme.passwordEnvVar != null) {
+ environmentVariables.push(scheme.passwordEnvVar);
+ }
+ break;
+ case "oauth":
+ if (scheme.configuration.type === "clientCredentials") {
+ if (scheme.configuration.clientIdEnvVar != null) {
+ environmentVariables.push(scheme.configuration.clientIdEnvVar);
+ }
+ if (scheme.configuration.clientSecretEnvVar != null) {
+ environmentVariables.push(scheme.configuration.clientSecretEnvVar);
+ }
+ }
+ break;
+ case "inferred":
+ break;
+ default:
+ assertNever(scheme);
+ }
+ }
+ return environmentVariables;
+ }
+
private getPrerenderedSnippetsForFeature(
featureId: FernGeneratorCli.FeatureId,
predicate: (endpoint: EndpointWithFilepath) => boolean = () => true
@@ -176,23 +245,82 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
}
private renderRequestOptionsSnippet(endpoint: EndpointWithFilepath): string {
- return this.writeCode(dedent`
- // Specify default options applied on every request.
- ${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient(
- option.${this.getBearerTokenOptionName()}("${this.getTokenPlaceholder()}"),
+ const authOptions = this.getAuthOptions();
+ const clientOptions = [
+ ...authOptions,
+ dedent`
option.WithHTTPClient(
&http.Client{
Timeout: 5 * time.Second,
},
- ),
- )
+ )`
+ ];
+ const requestOption = authOptions[0] ?? "option.WithMaxAttempts(1)";
+ const lines: string[] = [
+ "// Specify default options applied on every request.",
+ `${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient(`,
+ ...clientOptions.map((option) => `${this.indent(option)},`),
+ ")",
+ "",
+ "// Specify options for an individual request.",
+ `response, err := ${this.getMethodCall(endpoint)}(`,
+ " ...,",
+ ` ${requestOption},`,
+ ")"
+ ];
+ return this.writeCode(lines.join("\n"));
+ }
+
+ private getAuthOptions(): string[] {
+ const options: string[] = [];
+ for (const scheme of this.context.ir.auth?.schemes ?? []) {
+ switch (scheme.type) {
+ case "bearer":
+ options.push(
+ `option.With${this.context.caseConverter.pascalUnsafe(scheme.token)}("${
+ scheme.tokenPlaceholder ?? ""
+ }")`
+ );
+ break;
+ case "header":
+ options.push(
+ `option.With${this.context.caseConverter.pascalUnsafe(scheme.name)}("${
+ scheme.headerPlaceholder ?? ""
+ }")`
+ );
+ break;
+ case "basic": {
+ const basicAuthArguments: string[] = [];
+ if (scheme.usernameOmit !== true) {
+ basicAuthArguments.push(`"${scheme.usernamePlaceholder ?? ""}"`);
+ }
+ if (scheme.passwordOmit !== true) {
+ basicAuthArguments.push(`"${scheme.passwordPlaceholder ?? ""}"`);
+ }
+ if (basicAuthArguments.length > 0) {
+ options.push(`option.WithBasicAuth(${basicAuthArguments.join(", ")})`);
+ }
+ break;
+ }
+ case "oauth":
+ options.push(
+ `option.WithClientCredentials("${this.getOAuthClientIdPlaceholder()}", "${this.getOAuthClientSecretPlaceholder()}")`
+ );
+ break;
+ case "inferred":
+ break;
+ default:
+ assertNever(scheme);
+ }
+ }
+ return options;
+ }
- // Specify options for an individual request.
- response, err := ${this.getMethodCall(endpoint)}(
- ...,
- option.${this.getBearerTokenOptionName()}("${this.getTokenPlaceholder()}"),
- )
- `);
+ private indent(s: string): string {
+ return s
+ .split("\n")
+ .map((line) => (line.length > 0 ? ` ${line}` : line))
+ .join("\n");
}
private renderErrorsSnippet(endpoint: EndpointWithFilepath): string {
@@ -200,7 +328,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
response, err := ${this.getMethodCall(endpoint)}(...)
if err != nil {
var apiError *core.APIError
- if errors.As(err, apiError) {
+ if errors.As(err, &apiError) {
// Do something with the API error ...
}
return err
@@ -282,8 +410,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
}
// Paginated endpoints return a Page with directly accessible headers, status code, and full response
- ctx := context.TODO()
- page, err := ${this.getMethodCall(endpoint)}(
+ page, err = ${this.getMethodCall(endpoint)}(
ctx,
...
)
@@ -407,8 +534,27 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder {
}
private getEndpointsForFeature(featureId: FernIr.FeatureId): EndpointWithFilepath[] {
- const endpointIds = this.getConfiguredEndpointIdsForFeature(featureId) ?? [this.defaultEndpointId];
- return endpointIds.map(this.lookupEndpointById.bind(this));
+ const configuredEndpointIds = this.getConfiguredEndpointIdsForFeature(featureId);
+ if (configuredEndpointIds != null) {
+ return configuredEndpointIds.map(this.lookupEndpointById.bind(this));
+ }
+ if (featureId === FernGeneratorCli.StructuredFeatureId.Pagination) {
+ const paginatedEndpoint = this.getEndpointWithPagination();
+ if (paginatedEndpoint != null) {
+ return [paginatedEndpoint];
+ }
+ }
+ return [this.lookupEndpointById(this.defaultEndpointId)];
+ }
+
+ private getEndpointWithPagination(): EndpointWithFilepath | undefined {
+ const defaultEndpoint = this.endpointsById[this.defaultEndpointId];
+ if (defaultEndpoint != null && this.context.isEnabledPaginationEndpoint(defaultEndpoint.endpoint)) {
+ return defaultEndpoint;
+ }
+ return Object.values(this.endpointsById).find((endpoint) =>
+ this.context.isEnabledPaginationEndpoint(endpoint.endpoint)
+ );
}
private getConfiguredEndpointIdsForFeature(featureId: FernIr.FeatureId): FernIr.EndpointId[] | undefined {
diff --git a/generators/go/sdk/changes/1.57.4/fix-readme-snippets.yml b/generators/go/sdk/changes/1.57.4/fix-readme-snippets.yml
new file mode 100644
index 000000000000..d5bcb596191e
--- /dev/null
+++ b/generators/go/sdk/changes/1.57.4/fix-readme-snippets.yml
@@ -0,0 +1,18 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ Fix several issues in the generated README:
+ - The Request Options example now renders the auth options the SDK actually
+ generates (e.g., `option.WithSecret` for header auth, `option.WithBasicAuth`
+ for basic auth) instead of always assuming `option.WithToken`.
+ - The Errors example now passes a pointer to `errors.As` so the snippet
+ compiles and doesn't panic.
+ - The Pagination section is now emitted whenever the API has an endpoint
+ with a generated paginated client, by selecting such an endpoint for the
+ example, rather than relying on the default endpoint being paginated. The
+ section is omitted entirely when no paginated client is generated (e.g.
+ custom, URI, and path pagination), so the example no longer references an
+ iterator that doesn't exist.
+ - The Request Options section now documents the environment variables the
+ generated client reads credentials from when they aren't explicitly provided.
+ type: fix
diff --git a/generators/go/sdk/versions.yml b/generators/go/sdk/versions.yml
index 2b7ef5d4a6cd..8299c4fbd566 100644
--- a/generators/go/sdk/versions.yml
+++ b/generators/go/sdk/versions.yml
@@ -1,4 +1,24 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
+- version: 1.57.4
+ changelogEntry:
+ - summary: |
+ Fix several issues in the generated README:
+ - The Request Options example now renders the auth options the SDK actually
+ generates (e.g., `option.WithSecret` for header auth, `option.WithBasicAuth`
+ for basic auth) instead of always assuming `option.WithToken`.
+ - The Errors example now passes a pointer to `errors.As` so the snippet
+ compiles and doesn't panic.
+ - The Pagination section is now emitted whenever the API has an endpoint
+ with a generated paginated client, by selecting such an endpoint for the
+ example, rather than relying on the default endpoint being paginated. The
+ section is omitted entirely when no paginated client is generated (e.g.
+ custom, URI, and path pagination), so the example no longer references an
+ iterator that doesn't exist.
+ - The Request Options section now documents the environment variables the
+ generated client reads credentials from when they aren't explicitly provided.
+ type: fix
+ createdAt: "2026-08-20"
+ irVersion: 67
- version: 1.57.3
changelogEntry:
- summary: |
diff --git a/packages/cli/cli/build.dev.mjs b/packages/cli/cli/build.dev.mjs
index 4c4d88164da7..b2a02ae5471f 100644
--- a/packages/cli/cli/build.dev.mjs
+++ b/packages/cli/cli/build.dev.mjs
@@ -7,6 +7,8 @@ buildCli({
AUTH0_DOMAIN: "fern-dev.us.auth0.com",
AUTH0_CLIENT_ID: "4QiMvRvRUYpnycrVDK2M59hhJ6kcHYFQ",
DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator-dev2.buildwithfern.com",
+ DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman-beta.tech",
+ DEFAULT_USE_SDK_GEN_API: "false",
DEFAULT_VENUS_ORIGIN: "https://venus-dev2.buildwithfern.com",
DEFAULT_FDR_ORIGIN: "https://registry-dev2.buildwithfern.com",
DEFAULT_FAI_ORIGIN: "https://fai-dev2.buildwithfern.com",
diff --git a/packages/cli/cli/build.local.mjs b/packages/cli/cli/build.local.mjs
index 0bb5a9a4758b..74bf5f69130e 100644
--- a/packages/cli/cli/build.local.mjs
+++ b/packages/cli/cli/build.local.mjs
@@ -7,6 +7,8 @@ buildCli({
AUTH0_DOMAIN: "localhost:3100",
AUTH0_CLIENT_ID: "fern",
DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator-dev2.buildwithfern.com",
+ DEFAULT_SDK_GEN_API_ORIGIN: "http://localhost:3001",
+ DEFAULT_USE_SDK_GEN_API: "false",
DEFAULT_VENUS_ORIGIN: "http://localhost:8089",
DEFAULT_FDR_ORIGIN: "http://localhost:8080",
FERN_FDR_ORIGIN: "http://localhost:8080",
diff --git a/packages/cli/cli/build.prod-unminified.mjs b/packages/cli/cli/build.prod-unminified.mjs
index 2266ac12d1ce..9e91d5f15fa1 100644
--- a/packages/cli/cli/build.prod-unminified.mjs
+++ b/packages/cli/cli/build.prod-unminified.mjs
@@ -7,6 +7,8 @@ buildCli({
AUTH0_DOMAIN: "fern-prod.us.auth0.com",
AUTH0_CLIENT_ID: "syaWnk6SjNoo5xBf1omfvziU3q7085lh",
DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator.buildwithfern.com",
+ DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman.co",
+ DEFAULT_USE_SDK_GEN_API: "false",
DEFAULT_VENUS_ORIGIN: "https://venus.buildwithfern.com",
DEFAULT_FDR_ORIGIN: "https://registry.buildwithfern.com",
VENUS_AUDIENCE: "venus-prod",
diff --git a/packages/cli/cli/build.prod.mjs b/packages/cli/cli/build.prod.mjs
index 06604542d73c..f9e8334e87ef 100644
--- a/packages/cli/cli/build.prod.mjs
+++ b/packages/cli/cli/build.prod.mjs
@@ -7,6 +7,8 @@ buildCli({
AUTH0_DOMAIN: "fern-prod.us.auth0.com",
AUTH0_CLIENT_ID: "syaWnk6SjNoo5xBf1omfvziU3q7085lh",
DEFAULT_FIDDLE_ORIGIN: "https://fiddle-coordinator.buildwithfern.com",
+ DEFAULT_SDK_GEN_API_ORIGIN: "https://sdk-gen.postman.co",
+ DEFAULT_USE_SDK_GEN_API: "false",
DEFAULT_VENUS_ORIGIN: "https://venus.buildwithfern.com",
DEFAULT_FDR_ORIGIN: "https://registry.buildwithfern.com",
DEFAULT_FAI_ORIGIN: "https://fai.buildwithfern.com",
diff --git a/packages/cli/cli/changes/5.100.0/sdk-gen-api-backend.yml b/packages/cli/cli/changes/5.100.0/sdk-gen-api-backend.yml
new file mode 100644
index 000000000000..01c1bf638dbf
--- /dev/null
+++ b/packages/cli/cli/changes/5.100.0/sdk-gen-api-backend.yml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json
+
+- summary: |
+ Add an internal, default-disabled SDK generation route through sdk-gen-api. Preserve local
+ generation and non-SDK remote generators on their existing paths, and report unsupported
+ SDK migration features explicitly instead of silently falling back to Fiddle.
+ type: internal
diff --git a/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts b/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts
new file mode 100644
index 000000000000..37cfb6afd522
--- /dev/null
+++ b/packages/cli/cli/src/commands/generate/__test__/createSpecsTarGzCache.test.ts
@@ -0,0 +1,23 @@
+import { describe, expect, it, vi } from "vitest";
+import { createSpecsTarGzCache } from "../createSpecsTarGzCache.js";
+
+describe("createSpecsTarGzCache", () => {
+ it("shares one in-flight archive operation with concurrent generator tasks", async () => {
+ let resolveArchive: ((archive: Buffer) => void) | undefined;
+ const deferredArchive = new Promise((resolve) => {
+ resolveArchive = resolve;
+ });
+ const archiveFactory = vi.fn(() => deferredArchive);
+ const getArchive = createSpecsTarGzCache(archiveFactory);
+
+ const archiveRequests = [getArchive(), getArchive(), getArchive(), getArchive()];
+
+ expect(archiveFactory).toHaveBeenCalledTimes(1);
+ const archive = Buffer.from("shared-specs-archive");
+ resolveArchive?.(archive);
+
+ const results = await Promise.all(archiveRequests);
+ expect(results).toEqual([archive, archive, archive, archive]);
+ expect(results.every((result) => result === archive)).toBe(true);
+ });
+});
diff --git a/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts b/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts
new file mode 100644
index 000000000000..4d43fb9edc39
--- /dev/null
+++ b/packages/cli/cli/src/commands/generate/createSpecsTarGzCache.ts
@@ -0,0 +1,12 @@
+/**
+ * Memoizes both the in-flight archive operation and its result. Concurrent generator tasks must
+ * await the same promise; caching only a completion boolean allows siblings to observe an empty
+ * result while the first archive is still being built.
+ */
+export function createSpecsTarGzCache(createArchive: () => Promise): () => Promise {
+ let archivePromise: Promise | undefined;
+ return () => {
+ archivePromise ??= createArchive();
+ return archivePromise;
+ };
+}
diff --git a/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts b/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts
index 6a027dacb338..42def2513c6e 100644
--- a/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts
+++ b/packages/cli/cli/src/commands/generate/generateAPIWorkspace.ts
@@ -12,7 +12,9 @@ import {
AutomationRunOptions,
findGeneratorLineNumber,
GeneratorOccurrenceTracker,
+ getFernSdkGenApiLanguage,
getOutputRepoUrl,
+ isFernSdkGenApiEnabled,
runRemoteGenerationForAPIWorkspace
} from "@fern-api/remote-workspace-runner";
import { CliError, TaskContext } from "@fern-api/task-context";
@@ -20,6 +22,7 @@ import { AbstractAPIWorkspace } from "@fern-api/workspace-loader";
import { FernFiddle } from "@fern-fern/fiddle-sdk";
import { isTelemetryDisabled } from "../../telemetry/isTelemetryDisabled.js";
+import { createSpecsTarGzCache } from "./createSpecsTarGzCache.js";
import { filterGenerators } from "./filterGenerators.js";
import { GenerationMode } from "./generateAPIWorkspaces.js";
import { PackMode, packLocalOutputForGroup } from "./packLocalOutput.js";
@@ -193,21 +196,27 @@ export async function generateWorkspace({
});
} else if (token != null) {
// Lazily build the specs tar.gz once per group, only if a generator needs it
- let cachedSpecsTarGz: Buffer | undefined;
- let specsComputed = false;
+ const ossWorkspace = workspace instanceof OSSWorkspace ? workspace : undefined;
+ const getCachedSpecsTarGz =
+ ossWorkspace == null
+ ? undefined
+ : createSpecsTarGzCache(() =>
+ createSpecsTarGzBuffer({
+ specs: ossWorkspace.allSpecs,
+ context: groupContext,
+ audiences: group.audiences
+ })
+ );
const getSpecsTarGz = async (generatorName: string): Promise => {
- if (!(workspace instanceof OSSWorkspace) || !generatorWantsSpecs(generatorName)) {
+ const sdkGenApiNeedsSpecs =
+ isFernSdkGenApiEnabled() && getFernSdkGenApiLanguage(generatorName) != null;
+ if (
+ getCachedSpecsTarGz == null ||
+ (!generatorWantsSpecs(generatorName) && !sdkGenApiNeedsSpecs)
+ ) {
return undefined;
}
- if (!specsComputed) {
- specsComputed = true;
- cachedSpecsTarGz = await createSpecsTarGzBuffer({
- specs: workspace.allSpecs,
- context: groupContext,
- audiences: group.audiences
- });
- }
- return cachedSpecsTarGz;
+ return getCachedSpecsTarGz();
};
await runRemoteGenerationForAPIWorkspace({
diff --git a/packages/cli/cli/versions.yml b/packages/cli/cli/versions.yml
index 7aa898ebd838..8446269e4af3 100644
--- a/packages/cli/cli/versions.yml
+++ b/packages/cli/cli/versions.yml
@@ -1,4 +1,13 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
+- version: 5.100.0
+ changelogEntry:
+ - summary: |
+ Add an internal, default-disabled SDK generation route through sdk-gen-api. Preserve local
+ generation and non-SDK remote generators on their existing paths, and report unsupported
+ SDK migration features explicitly instead of silently falling back to Fiddle.
+ type: internal
+ createdAt: "2026-08-20"
+ irVersion: 67
- version: 5.99.1
changelogEntry:
- summary: |
diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/csharp-xml-entities/type__TimeZoneModel.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/csharp-xml-entities/type__TimeZoneModel.json
index dbc06b87f333..f21745dd2610 100644
--- a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/csharp-xml-entities/type__TimeZoneModel.json
+++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/csharp-xml-entities/type__TimeZoneModel.json
@@ -23,6 +23,28 @@
}
],
"description": "Special characters: … · ©"
+ },
+ "documentationLink": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "See see here for details"
+ },
+ "escapedDocumentationLink": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "See see here for details"
}
},
"required": [
diff --git a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json
index 9d4c6f844bc3..fc2602a3fbed 100644
--- a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json
+++ b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/csharp-xml-entities.json
@@ -152,6 +152,72 @@
},
"propertyAccess": null,
"variable": null
+ },
+ {
+ "name": {
+ "wireValue": "documentationLink",
+ "name": {
+ "originalName": "documentationLink",
+ "camelCase": {
+ "unsafeName": "documentationLink",
+ "safeName": "documentationLink"
+ },
+ "snakeCase": {
+ "unsafeName": "documentation_link",
+ "safeName": "documentation_link"
+ },
+ "screamingSnakeCase": {
+ "unsafeName": "DOCUMENTATION_LINK",
+ "safeName": "DOCUMENTATION_LINK"
+ },
+ "pascalCase": {
+ "unsafeName": "DocumentationLink",
+ "safeName": "DocumentationLink"
+ }
+ }
+ },
+ "typeReference": {
+ "type": "optional",
+ "value": {
+ "type": "primitive",
+ "value": "STRING"
+ }
+ },
+ "propertyAccess": null,
+ "variable": null
+ },
+ {
+ "name": {
+ "wireValue": "escapedDocumentationLink",
+ "name": {
+ "originalName": "escapedDocumentationLink",
+ "camelCase": {
+ "unsafeName": "escapedDocumentationLink",
+ "safeName": "escapedDocumentationLink"
+ },
+ "snakeCase": {
+ "unsafeName": "escaped_documentation_link",
+ "safeName": "escaped_documentation_link"
+ },
+ "screamingSnakeCase": {
+ "unsafeName": "ESCAPED_DOCUMENTATION_LINK",
+ "safeName": "ESCAPED_DOCUMENTATION_LINK"
+ },
+ "pascalCase": {
+ "unsafeName": "EscapedDocumentationLink",
+ "safeName": "EscapedDocumentationLink"
+ }
+ }
+ },
+ "typeReference": {
+ "type": "optional",
+ "value": {
+ "type": "primitive",
+ "value": "STRING"
+ }
+ },
+ "propertyAccess": null,
+ "variable": null
}
],
"extends": null,
diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json
index c5fc67ca619d..be09340c8d40 100644
--- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json
+++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/csharp-xml-entities.json
@@ -123,6 +123,62 @@
},
"availability": null,
"docs": "Special characters: … · ©"
+ },
+ {
+ "name": "documentationLink",
+ "valueType": {
+ "_type": "container",
+ "container": {
+ "_type": "optional",
+ "optional": {
+ "_type": "primitive",
+ "primitive": {
+ "v1": "STRING",
+ "v2": {
+ "type": "string",
+ "default": null,
+ "validation": null
+ }
+ }
+ }
+ }
+ },
+ "propertyAccess": null,
+ "defaultValue": null,
+ "v2Examples": {
+ "userSpecifiedExamples": {},
+ "autogeneratedExamples": {}
+ },
+ "availability": null,
+ "docs": "See see here for details"
+ },
+ {
+ "name": "escapedDocumentationLink",
+ "valueType": {
+ "_type": "container",
+ "container": {
+ "_type": "optional",
+ "optional": {
+ "_type": "primitive",
+ "primitive": {
+ "v1": "STRING",
+ "v2": {
+ "type": "string",
+ "default": null,
+ "validation": null
+ }
+ }
+ }
+ }
+ },
+ "propertyAccess": null,
+ "defaultValue": null,
+ "v2Examples": {
+ "userSpecifiedExamples": {},
+ "autogeneratedExamples": {}
+ },
+ "availability": null,
+ "docs": "See see here for details"
}
],
"extra-properties": false,
@@ -227,7 +283,7 @@
"autogeneratedExamples": [
{
"example": {
- "id": "9edac0cd",
+ "id": "da856427",
"url": "/timezone",
"name": null,
"endpointHeaders": [],
@@ -370,6 +426,98 @@
"jsonExample": "specialChars"
},
"propertyAccess": null
+ },
+ {
+ "name": "documentationLink",
+ "originalTypeDeclaration": {
+ "name": "TimeZoneModel",
+ "fernFilepath": {
+ "allParts": [],
+ "packagePath": [],
+ "file": null
+ },
+ "displayName": null,
+ "typeId": "type_:TimeZoneModel"
+ },
+ "value": {
+ "shape": {
+ "type": "container",
+ "container": {
+ "type": "optional",
+ "optional": {
+ "shape": {
+ "type": "primitive",
+ "primitive": {
+ "type": "string",
+ "string": {
+ "original": "documentationLink"
+ }
+ }
+ },
+ "jsonExample": "documentationLink"
+ },
+ "valueType": {
+ "_type": "primitive",
+ "primitive": {
+ "v1": "STRING",
+ "v2": {
+ "type": "string",
+ "default": null,
+ "validation": null
+ }
+ }
+ }
+ }
+ },
+ "jsonExample": "documentationLink"
+ },
+ "propertyAccess": null
+ },
+ {
+ "name": "escapedDocumentationLink",
+ "originalTypeDeclaration": {
+ "name": "TimeZoneModel",
+ "fernFilepath": {
+ "allParts": [],
+ "packagePath": [],
+ "file": null
+ },
+ "displayName": null,
+ "typeId": "type_:TimeZoneModel"
+ },
+ "value": {
+ "shape": {
+ "type": "container",
+ "container": {
+ "type": "optional",
+ "optional": {
+ "shape": {
+ "type": "primitive",
+ "primitive": {
+ "type": "string",
+ "string": {
+ "original": "escapedDocumentationLink"
+ }
+ }
+ },
+ "jsonExample": "escapedDocumentationLink"
+ },
+ "valueType": {
+ "_type": "primitive",
+ "primitive": {
+ "v1": "STRING",
+ "v2": {
+ "type": "string",
+ "default": null,
+ "validation": null
+ }
+ }
+ }
+ }
+ },
+ "jsonExample": "escapedDocumentationLink"
+ },
+ "propertyAccess": null
}
],
"extraProperties": null
@@ -389,7 +537,9 @@
"timeZoneOffset": "timeZoneOffset",
"mathExpression": "mathExpression",
"validEntity": "validEntity",
- "specialChars": "specialChars"
+ "specialChars": "specialChars",
+ "documentationLink": "documentationLink",
+ "escapedDocumentationLink": "escapedDocumentationLink"
}
}
}
@@ -592,6 +742,72 @@
},
"propertyAccess": null,
"variable": null
+ },
+ {
+ "name": {
+ "wireValue": "documentationLink",
+ "name": {
+ "originalName": "documentationLink",
+ "camelCase": {
+ "unsafeName": "documentationLink",
+ "safeName": "documentationLink"
+ },
+ "snakeCase": {
+ "unsafeName": "documentation_link",
+ "safeName": "documentation_link"
+ },
+ "screamingSnakeCase": {
+ "unsafeName": "DOCUMENTATION_LINK",
+ "safeName": "DOCUMENTATION_LINK"
+ },
+ "pascalCase": {
+ "unsafeName": "DocumentationLink",
+ "safeName": "DocumentationLink"
+ }
+ }
+ },
+ "typeReference": {
+ "type": "optional",
+ "value": {
+ "type": "primitive",
+ "value": "STRING"
+ }
+ },
+ "propertyAccess": null,
+ "variable": null
+ },
+ {
+ "name": {
+ "wireValue": "escapedDocumentationLink",
+ "name": {
+ "originalName": "escapedDocumentationLink",
+ "camelCase": {
+ "unsafeName": "escapedDocumentationLink",
+ "safeName": "escapedDocumentationLink"
+ },
+ "snakeCase": {
+ "unsafeName": "escaped_documentation_link",
+ "safeName": "escaped_documentation_link"
+ },
+ "screamingSnakeCase": {
+ "unsafeName": "ESCAPED_DOCUMENTATION_LINK",
+ "safeName": "ESCAPED_DOCUMENTATION_LINK"
+ },
+ "pascalCase": {
+ "unsafeName": "EscapedDocumentationLink",
+ "safeName": "EscapedDocumentationLink"
+ }
+ }
+ },
+ "typeReference": {
+ "type": "optional",
+ "value": {
+ "type": "primitive",
+ "value": "STRING"
+ }
+ },
+ "propertyAccess": null,
+ "variable": null
}
],
"extends": null,
diff --git a/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts b/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts
index 2afc0c07a670..a5afc17cbeac 100644
--- a/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts
+++ b/packages/cli/generation/local-generation/local-workspace-runner/src/rawSpecs.ts
@@ -432,7 +432,7 @@ function hasOperations(pathItem: Record): boolean {
/**
* Collects raw API specs, writes them to a temporary directory alongside a
* manifest, and packages everything into a gzipped tar archive suitable for
- * uploading to Fiddle's `startJob` endpoint.
+ * remote generation backends.
*/
export async function createSpecsTarGzBuffer({
specs,
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts
index 8246abc3cf6f..fa91f02c018f 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/RemoteTaskHandler.ts
@@ -442,26 +442,28 @@ function extractGithubModeFromGenerator(
return "push";
}
-async function downloadFilesForTask({
+export async function downloadFilesForTask({
s3PreSignedReadUrl,
absolutePathToLocalOutput,
- context
+ context,
+ skipFernignore = false
}: {
s3PreSignedReadUrl: string;
absolutePathToLocalOutput: AbsoluteFilePath;
context: InteractiveTaskContext;
-}) {
+ skipFernignore?: boolean;
+}): Promise {
try {
const isFernIgnorePresent = await checkFernIgnorePresent(absolutePathToLocalOutput);
const isExistingGitRepo = await checkIsGitRepository(absolutePathToLocalOutput);
- if (isFernIgnorePresent && isExistingGitRepo) {
+ if (!skipFernignore && isFernIgnorePresent && isExistingGitRepo) {
await downloadFilesWithFernIgnoreInExistingRepo({
s3PreSignedReadUrl,
absolutePathToLocalOutput,
context
});
- } else if (isFernIgnorePresent && !isExistingGitRepo) {
+ } else if (!skipFernignore && isFernIgnorePresent && !isExistingGitRepo) {
await downloadFilesWithFernIgnoreInTempRepo({
s3PreSignedReadUrl,
absolutePathToLocalOutput,
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts
new file mode 100644
index 000000000000..d3ef401ff238
--- /dev/null
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/__test__/fernSdkGenApi.test.ts
@@ -0,0 +1,502 @@
+import { generatorsYml } from "@fern-api/configuration";
+import { FernFiddle } from "@fern-fern/fiddle-sdk";
+import axios from "axios";
+import { afterEach, describe, expect, it, vi } from "vitest";
+import {
+ createFernSdkGenApiBatchRequest,
+ createFernSdkGenApiRequest,
+ FernSdkGenApiBatch,
+ getFernSdkGenApiLanguage,
+ getFernSdkGenApiOrigin,
+ isEligibleForFernSdkGenApi,
+ isFernSdkGenApiEnabled,
+ runFernSdkGenApiBuild
+} from "../fernSdkGenApi.js";
+
+afterEach(() => {
+ vi.restoreAllMocks();
+ vi.unstubAllEnvs();
+});
+
+function invocation(overrides: Record = {}): generatorsYml.GeneratorInvocation {
+ return {
+ name: "fernapi/fern-typescript-sdk",
+ version: "3.86.0",
+ language: "typescript",
+ config: {},
+ keywords: [],
+ smartCasing: true,
+ smartCasingDigitWordBoundary: false,
+ disableExamples: false,
+ outputMode: { type: "downloadFiles" },
+ ...overrides
+ } as unknown as generatorsYml.GeneratorInvocation;
+}
+
+describe("isEligibleForFernSdkGenApi", () => {
+ it("selects first-party SDK generators in every supported language", () => {
+ const generators = [
+ ["fernapi/fern-typescript-sdk", "typescript"],
+ ["fernapi/fern-python-sdk", "python"],
+ ["fernapi/fern-java-sdk", "java"],
+ ["fernapi/fern-kotlin-sdk", "kotlin"],
+ ["fernapi/fern-go-sdk", "go"],
+ ["fernapi/fern-csharp-sdk", "csharp"],
+ ["fernapi/fern-php-sdk", "php"],
+ ["fernapi/fern-ruby-sdk", "ruby"],
+ ["fernapi/fern-rust-sdk", "rust"],
+ ["fernapi/fern-swift-sdk", "swift"],
+ ["fernapi/fern-cli-generator", "cli"]
+ ] as const;
+
+ for (const [name, language] of generators) {
+ expect(getFernSdkGenApiLanguage(name)).toBe(language);
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation({ name, language }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(true);
+ }
+ });
+
+ it("retains configured invocations on the sdk-gen-api route", () => {
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation({
+ config: { packageJson: { name: "@acme/sdk" } }
+ }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(true);
+ });
+
+ it("rejects non-SDK generators and unresolved SDK versions", () => {
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation({
+ name: "fernapi/fern-typescript-express"
+ }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(false);
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation(),
+ sdkVersion: undefined,
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(false);
+ });
+
+ it("routes GitHub and registry output through sdk-gen-api", () => {
+ const outputs = [
+ FernFiddle.OutputMode.githubV2(
+ FernFiddle.GithubOutputModeV2.push({
+ owner: "acme",
+ repo: "sdk",
+ branch: "main"
+ })
+ ),
+ FernFiddle.OutputMode.publishV2(
+ FernFiddle.PublishOutputModeV2.npmOverride({
+ registryUrl: "https://registry.npmjs.org",
+ packageName: "@acme/sdk",
+ token: "secret"
+ })
+ )
+ ];
+
+ for (const outputMode of outputs) {
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation({ outputMode }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(true);
+ }
+ });
+
+ it("rejects AUTO until the shared pipeline owns Fern's post-generation version replacement", () => {
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation(),
+ sdkVersion: "AUTO",
+ specsTarGzBuffer: Buffer.from("archive")
+ })
+ ).toBe(false);
+ });
+
+ it("rejects whitelabel builds until the shared pipeline can preserve their branding behavior", () => {
+ expect(
+ isEligibleForFernSdkGenApi({
+ generatorInvocation: invocation(),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive"),
+ whitelabel: {
+ github: { token: "token", username: "fern", email: "fern@example.com" }
+ }
+ })
+ ).toBe(false);
+ });
+
+ it("references every source in the uploaded archive", () => {
+ const request = createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation: invocation(),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ });
+
+ expect(request.apiInputs).toEqual([{ id: "default", specIndexes: "all" }]);
+ expect(request.targets[0]).toMatchObject({
+ language: "typescript",
+ invocation: {
+ customConfig: {},
+ keywords: [],
+ smartCasing: true,
+ smartCasingDigitWordBoundary: false,
+ disableExamples: false
+ }
+ });
+ expect(request.targets[0]?.invocation).not.toHaveProperty("audiences");
+ });
+
+ it("preserves an explicitly selected audience list", () => {
+ const request = createFernSdkGenApiBatchRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ specsTarGzBuffer: Buffer.from("archive"),
+ targets: [
+ {
+ generatorInvocation: invocation(),
+ sdkVersion: "1.2.3",
+ audiences: ["public"]
+ }
+ ]
+ });
+
+ expect(request.targets[0]?.invocation.audiences).toEqual(["public"]);
+ });
+
+ it("uses the generator language instead of hard-coding TypeScript", () => {
+ const request = createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation: invocation({
+ name: "fernapi/fern-python-sdk",
+ language: "python",
+ version: "4.64.1"
+ }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ });
+
+ expect(request.targets[0]?.language).toBe("python");
+ });
+
+ it("maps GitHub delivery and optional registry publication", () => {
+ const request = createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation: invocation({
+ outputMode: FernFiddle.OutputMode.githubV2(
+ FernFiddle.GithubOutputModeV2.pullRequest({
+ owner: "acme",
+ repo: "typescript-sdk",
+ host: "github.example.com",
+ branch: "develop",
+ reviewers: [
+ FernFiddle.GithubPullRequestReviewer.team({
+ name: "sdk-reviewers"
+ }),
+ FernFiddle.GithubPullRequestReviewer.user({ name: "octocat" })
+ ],
+ publishInfo: FernFiddle.GithubPublishInfo.npm({
+ registryUrl: "https://registry.npmjs.org",
+ packageName: "@acme/typescript-sdk"
+ })
+ })
+ )
+ }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ });
+
+ expect(request.targets[0]).toMatchObject({
+ package: { packageName: "@acme/typescript-sdk" },
+ requestedOutput: {
+ type: "github",
+ repository: "acme/typescript-sdk",
+ host: "github.example.com",
+ branch: "develop",
+ mode: "pull-request",
+ reviewers: { teams: ["sdk-reviewers"], users: ["octocat"] },
+ publish: { registry: "npm", url: "https://registry.npmjs.org" }
+ }
+ });
+ expect(JSON.stringify(request)).not.toContain("secret");
+ });
+
+ it("maps direct registry publication and package identity", () => {
+ const request = createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation: invocation({
+ name: "fernapi/fern-python-sdk",
+ language: "python",
+ outputMode: FernFiddle.OutputMode.publishV2(
+ FernFiddle.PublishOutputModeV2.pypiOverride({
+ registryUrl: "https://upload.pypi.org/legacy/",
+ coordinate: "acme-sdk",
+ username: "__token__",
+ password: "secret"
+ })
+ )
+ }),
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ });
+
+ expect(request.targets[0]).toMatchObject({
+ package: { packageName: "acme-sdk" },
+ requestedOutput: {
+ type: "publish",
+ publish: { registry: "pypi", url: "https://upload.pypi.org/legacy/" }
+ }
+ });
+ expect(JSON.stringify(request)).not.toContain("secret");
+ });
+
+ it("creates one request for a group with multiple languages and duplicate-language targets", () => {
+ const request = createFernSdkGenApiBatchRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ specsTarGzBuffer: Buffer.from("archive"),
+ targets: [
+ {
+ generatorInvocation: invocation(),
+ sdkVersion: "1.2.3",
+ targetIdSeed: "0"
+ },
+ {
+ generatorInvocation: invocation({
+ name: "fernapi/fern-python-sdk",
+ language: "python",
+ version: "4.64.1"
+ }),
+ sdkVersion: "1.2.3",
+ targetIdSeed: "1"
+ },
+ {
+ generatorInvocation: invocation(),
+ sdkVersion: "2.0.0",
+ targetIdSeed: "2"
+ }
+ ]
+ });
+
+ expect(request.targets.map((target) => target.language)).toEqual(["typescript", "python", "typescript"]);
+ expect(new Set(request.targets.map((target) => target.targetId)).size).toBe(3);
+ });
+
+ it("changes the idempotency key when generator configuration or output changes", () => {
+ const createRequest = (generatorInvocation: generatorsYml.GeneratorInvocation) =>
+ createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation,
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer: Buffer.from("archive")
+ });
+
+ const original = createRequest(invocation());
+ const configured = createRequest(invocation({ config: { packageJson: { name: "@acme/sdk" } } }));
+ const github = createRequest(
+ invocation({
+ outputMode: FernFiddle.OutputMode.githubV2(
+ FernFiddle.GithubOutputModeV2.push({ owner: "acme", repo: "sdk", branch: "main" })
+ )
+ })
+ );
+
+ expect(configured.idempotencyKey).not.toBe(original.idempotencyKey);
+ expect(github.idempotencyKey).not.toBe(original.idempotencyKey);
+ });
+
+ it("submits and polls a multi-language group once", async () => {
+ process.env.FERN_SDK_GEN_API_ORIGIN = "https://sdk-gen-api.test";
+ const specsTarGzBuffer = Buffer.from("archive");
+ const typescript = invocation();
+ const python = invocation({
+ name: "fernapi/fern-python-sdk",
+ language: "python",
+ version: "4.64.1"
+ });
+ const request = createFernSdkGenApiBatchRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ specsTarGzBuffer,
+ targets: [
+ {
+ generatorInvocation: typescript,
+ sdkVersion: "1.2.3",
+ targetIdSeed: "0"
+ },
+ { generatorInvocation: python, sdkVersion: "1.2.3", targetIdSeed: "1" }
+ ]
+ });
+ const post = vi.spyOn(axios, "post").mockResolvedValue({ data: { buildId: "build-1" } } as never);
+ const get = vi.spyOn(axios, "get").mockResolvedValue({
+ data: {
+ buildId: "build-1",
+ status: "succeeded",
+ targets: request.targets.map((target) => ({
+ targetId: target.targetId,
+ status: "succeeded",
+ logs: [],
+ result: {
+ artifactUrl: `https://example.test/${target.targetId}.zip`
+ }
+ }))
+ }
+ } as never);
+ const context = {
+ logger: { debug: vi.fn(), info: vi.fn() },
+ failAndThrow: (message: string) => {
+ throw new Error(message);
+ }
+ } as never;
+ const common = {
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ sdkVersion: "1.2.3",
+ token: { value: "token" } as never,
+ specsTarGzBuffer,
+ absolutePathToPreview: undefined,
+ context
+ };
+ const batch = new FernSdkGenApiBatch(2);
+
+ const results = await Promise.all([
+ batch.run({
+ ...common,
+ generatorInvocation: typescript,
+ targetIdSeed: "0"
+ }),
+ batch.run({ ...common, generatorInvocation: python, targetIdSeed: "1" })
+ ]);
+
+ expect(post).toHaveBeenCalledTimes(1);
+ expect(get).toHaveBeenCalledTimes(1);
+ expect(results.map((result) => result.actualVersion)).toEqual(["1.2.3", "1.2.3"]);
+ });
+
+ it("stops polling when the build fails before a target reaches a terminal state", async () => {
+ process.env.FERN_SDK_GEN_API_ORIGIN = "https://sdk-gen-api.test";
+ const specsTarGzBuffer = Buffer.from("archive");
+ const generatorInvocation = invocation();
+ const request = createFernSdkGenApiRequest({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation,
+ sdkVersion: "1.2.3",
+ specsTarGzBuffer
+ });
+ vi.spyOn(axios, "post").mockResolvedValue({ data: { buildId: "build-1" } } as never);
+ const get = vi.spyOn(axios, "get").mockResolvedValue({
+ data: {
+ buildId: "build-1",
+ status: "failed",
+ targets: [{ targetId: request.targets[0]?.targetId, status: "queued", logs: [] }]
+ }
+ } as never);
+ const context = {
+ logger: { debug: vi.fn(), info: vi.fn() },
+ failAndThrow: (message: string) => {
+ throw new Error(message);
+ }
+ } as never;
+
+ await expect(
+ runFernSdkGenApiBuild({
+ apiName: "Petstore",
+ organization: "acme",
+ cliVersion: "0.0.0",
+ generatorInvocation,
+ sdkVersion: "1.2.3",
+ token: { value: "token" } as never,
+ specsTarGzBuffer,
+ absolutePathToPreview: undefined,
+ context
+ })
+ ).rejects.toThrow("build ended with status failed");
+ expect(get).toHaveBeenCalledTimes(1);
+ });
+});
+
+describe("sdk-gen-api environment configuration", () => {
+ it("is disabled by default", () => {
+ vi.stubEnv("FERN_USE_SDK_GEN_API", undefined);
+ vi.stubEnv("DEFAULT_USE_SDK_GEN_API", undefined);
+
+ expect(isFernSdkGenApiEnabled()).toBe(false);
+ });
+
+ it("uses the baked default when no runtime override is present", () => {
+ vi.stubEnv("FERN_USE_SDK_GEN_API", undefined);
+ vi.stubEnv("DEFAULT_USE_SDK_GEN_API", " true ");
+
+ expect(isFernSdkGenApiEnabled()).toBe(true);
+ });
+
+ it("lets the runtime flag override the baked default", () => {
+ vi.stubEnv("FERN_USE_SDK_GEN_API", "false");
+ vi.stubEnv("DEFAULT_USE_SDK_GEN_API", "true");
+
+ expect(isFernSdkGenApiEnabled()).toBe(false);
+ });
+
+ it("prefers the runtime origin and removes its trailing slash", () => {
+ vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "https://override.example.test/");
+ vi.stubEnv("DEFAULT_SDK_GEN_API_ORIGIN", "https://default.example.test");
+
+ expect(getFernSdkGenApiOrigin()).toBe("https://override.example.test");
+ });
+
+ it("uses the baked origin when no runtime override is present", () => {
+ vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", undefined);
+ vi.stubEnv("DEFAULT_SDK_GEN_API_ORIGIN", "https://default.example.test/");
+
+ expect(getFernSdkGenApiOrigin()).toBe("https://default.example.test");
+ });
+
+ it("allows HTTP only for loopback development origins", () => {
+ vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://localhost:3001/");
+ expect(getFernSdkGenApiOrigin()).toBe("http://localhost:3001");
+
+ vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://127.0.0.1:3001/");
+ expect(getFernSdkGenApiOrigin()).toBe("http://127.0.0.1:3001");
+ });
+
+ it("rejects insecure remote origins", () => {
+ vi.stubEnv("FERN_SDK_GEN_API_ORIGIN", "http://sdk-gen-api.example.test");
+
+ expect(() => getFernSdkGenApiOrigin()).toThrow("must use HTTPS unless it targets localhost");
+ });
+});
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts
new file mode 100644
index 000000000000..87fc990fd8d1
--- /dev/null
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/fernSdkGenApi.ts
@@ -0,0 +1,895 @@
+import { stripCliConfigKeys } from "@fern-api/api-workspace-commons";
+import { FernToken } from "@fern-api/auth";
+import { generatorsYml } from "@fern-api/configuration";
+import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils";
+import { isAutoVersion } from "@fern-api/generator-cli/autoversion";
+import { CliError, InteractiveTaskContext } from "@fern-api/task-context";
+import { FernFiddle } from "@fern-fern/fiddle-sdk";
+import axios, { AxiosError } from "axios";
+import { createHash } from "crypto";
+import FormData from "form-data";
+import path from "path";
+import { downloadFilesForTask } from "./RemoteTaskHandler.js";
+
+const POLL_INTERVAL_MS = 2_000;
+const POLL_TIMEOUT_MS = 15 * 60 * 1_000;
+const REQUEST_TIMEOUT_MS = 60_000;
+const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
+
+export type FernSdkGenApiLanguage =
+ | "typescript"
+ | "python"
+ | "java"
+ | "kotlin"
+ | "go"
+ | "csharp"
+ | "php"
+ | "ruby"
+ | "rust"
+ | "swift"
+ | "cli";
+
+export type FernSdkGenApiPublishRegistry =
+ | "npm"
+ | "pypi"
+ | "maven"
+ | "nuget"
+ | "rubygems"
+ | "crates"
+ | "go"
+ | "composer";
+
+export interface FernSdkGenApiPublishConfig {
+ registry: FernSdkGenApiPublishRegistry;
+ url?: string;
+}
+
+export interface FernSdkGenApiPackageConfig {
+ packageName?: string;
+ moduleName?: string;
+ modulePath?: string;
+ namespace?: string;
+ groupId?: string;
+ artifactId?: string;
+}
+
+export type FernSdkGenApiRequestedOutput =
+ | { type: "download" }
+ | {
+ type: "github";
+ repository: string;
+ host?: string;
+ branch?: string;
+ mode?: "release" | "pull-request" | "push";
+ reviewers?: { teams?: string[]; users?: string[] };
+ publish?: FernSdkGenApiPublishConfig;
+ }
+ | { type: "publish"; publish: FernSdkGenApiPublishConfig };
+
+/**
+ * First-party Fern SDK generators that can be represented by the shared SDK Config IR target
+ * languages. Keep aliases here because existing generators.yml files remain valid during the
+ * backend migration.
+ */
+const FERN_SDK_GENERATOR_LANGUAGES: Readonly> = {
+ "fernapi/fern-typescript": "typescript",
+ "fernapi/fern-typescript-sdk": "typescript",
+ "fernapi/fern-typescript-node-sdk": "typescript",
+ "fernapi/fern-typescript-browser-sdk": "typescript",
+ "fernapi/fern-python-sdk": "python",
+ "fernapi/fern-java-sdk": "java",
+ "fernapi/fern-kotlin-sdk": "kotlin",
+ "fernapi/fern-go-sdk": "go",
+ "fernapi/fern-csharp-sdk": "csharp",
+ "fernapi/fern-php-sdk": "php",
+ "fernapi/fern-ruby-sdk": "ruby",
+ "fernapi/fern-ruby-sdk-v2": "ruby",
+ "fernapi/fern-rust-sdk": "rust",
+ "fernapi/fern-swift-sdk": "swift",
+ "fernapi/fern-cli": "cli",
+ "fernapi/fern-cli-generator": "cli"
+};
+
+interface FernBuildStatus {
+ buildId: string;
+ status: "queued" | "running" | "succeeded" | "failed" | "partial_failure";
+ targets: Array<{
+ targetId: string;
+ status: "queued" | "running" | "succeeded" | "failed";
+ logs: Array<{ level: string; message: string }>;
+ result?: { artifactUrl: string; actualVersion?: string };
+ error?: { message: string };
+ }>;
+}
+
+export interface FernSdkGenApiRequest {
+ protocolVersion: 1;
+ apiName: string;
+ cliVersion?: string;
+ idempotencyKey: string;
+ apiInputs: Array<{ id: string; specIndexes: "all" }>;
+ targets: Array<{
+ targetId: string;
+ apiInputId: string;
+ language: FernSdkGenApiLanguage;
+ sdk: { name: string; version: string };
+ fernGenerator: { id: string; version: string };
+ package?: FernSdkGenApiPackageConfig;
+ invocation: {
+ customConfig: Record;
+ keywords: string[];
+ smartCasing: boolean;
+ smartCasingDigitWordBoundary: boolean;
+ disableExamples: boolean;
+ audiences?: string[];
+ readme?: Record;
+ settings?: Record;
+ apiOverride?: Record;
+ };
+ requestedOutput: FernSdkGenApiRequestedOutput;
+ }>;
+}
+
+export function isFernSdkGenApiEnabled(): boolean {
+ const configured = process.env.FERN_USE_SDK_GEN_API ?? process.env.DEFAULT_USE_SDK_GEN_API ?? "false";
+ return configured.trim().toLowerCase() === "true";
+}
+
+export function getFernSdkGenApiOrigin(): string | undefined {
+ const configured = process.env.FERN_SDK_GEN_API_ORIGIN ?? process.env.DEFAULT_SDK_GEN_API_ORIGIN;
+ if (configured == null) {
+ return undefined;
+ }
+
+ let origin: URL;
+ try {
+ origin = new URL(configured);
+ } catch {
+ throw new Error("FERN_SDK_GEN_API_ORIGIN must be a valid URL");
+ }
+ if (origin.username.length > 0 || origin.password.length > 0) {
+ throw new Error("FERN_SDK_GEN_API_ORIGIN must not contain credentials");
+ }
+ const isLoopbackHttp = origin.protocol === "http:" && LOOPBACK_HOSTNAMES.has(origin.hostname);
+ if (origin.protocol !== "https:" && !isLoopbackHttp) {
+ throw new Error("FERN_SDK_GEN_API_ORIGIN must use HTTPS unless it targets localhost");
+ }
+ return origin.toString().replace(/\/$/, "");
+}
+
+export function getFernSdkGenApiLanguage(generatorName: string): FernSdkGenApiLanguage | undefined {
+ return FERN_SDK_GENERATOR_LANGUAGES[generatorName];
+}
+
+interface FernSdkGenApiOutputMapping {
+ package?: FernSdkGenApiPackageConfig;
+ requestedOutput: FernSdkGenApiRequestedOutput;
+}
+
+/**
+ * Preserves Fern's delivery and publication intent without forwarding credentials. The shared
+ * config contract carries externally managed credential references; resolving Fern secrets into
+ * those references belongs to the downstream distribution workstream.
+ */
+export function mapFernSdkGenApiOutput(
+ generatorInvocation: generatorsYml.GeneratorInvocation
+): FernSdkGenApiOutputMapping {
+ const outputMode = generatorInvocation.outputMode;
+ switch (outputMode.type) {
+ case "downloadFiles":
+ return { requestedOutput: { type: "download" } };
+ case "github":
+ return mapGithubOutput({
+ owner: outputMode.owner,
+ repo: outputMode.repo,
+ branch: outputMode.branch,
+ mode: outputMode.makePr === true ? "pull-request" : "release",
+ publishInfo: outputMode.publishInfo
+ });
+ case "githubV2": {
+ const github = outputMode.githubV2;
+ return mapGithubOutput({
+ owner: github.owner,
+ repo: github.repo,
+ host: github.host,
+ branch: github.branch,
+ mode: github.type === "pullRequest" ? "pull-request" : github.type === "push" ? "push" : "release",
+ reviewers: github.type === "pullRequest" ? mapGithubReviewers(github.reviewers) : undefined,
+ publishInfo: github.publishInfo
+ });
+ }
+ case "publishV2": {
+ const mapped = mapPublishOutputV2(outputMode.publishV2);
+ return {
+ ...(mapped.package != null ? { package: mapped.package } : {}),
+ requestedOutput: { type: "publish", publish: mapped.publish }
+ };
+ }
+ case "publish": {
+ const mapped = mapLegacyPublishOutput(generatorInvocation, outputMode.registryOverrides);
+ return {
+ ...(mapped.package != null ? { package: mapped.package } : {}),
+ requestedOutput: { type: "publish", publish: mapped.publish }
+ };
+ }
+ }
+}
+
+function mapGithubOutput({
+ owner,
+ repo,
+ host,
+ branch,
+ mode,
+ reviewers,
+ publishInfo
+}: {
+ owner: string;
+ repo: string;
+ host?: string;
+ branch?: string;
+ mode: "release" | "pull-request" | "push";
+ reviewers?: { teams?: string[]; users?: string[] };
+ publishInfo?: FernFiddle.GithubPublishInfo;
+}): FernSdkGenApiOutputMapping {
+ const publication = publishInfo != null ? mapGithubPublishInfo(publishInfo) : undefined;
+ // TODO: Before broadly enabling this route, require downstream credential resolution to bind
+ // credentials to approved GitHub installations/repositories and registry hosts/package namespaces.
+ return {
+ ...(publication?.package != null ? { package: publication.package } : {}),
+ requestedOutput: {
+ type: "github",
+ repository: `${owner}/${repo}`,
+ ...(host != null ? { host } : {}),
+ ...(branch != null ? { branch } : {}),
+ mode,
+ ...(reviewers != null ? { reviewers } : {}),
+ ...(publication != null ? { publish: publication.publish } : {})
+ }
+ };
+}
+
+function mapGithubReviewers(
+ reviewers: FernFiddle.GithubPullRequestReviewer[] | undefined
+): { teams?: string[]; users?: string[] } | undefined {
+ if (reviewers == null) {
+ return undefined;
+ }
+ const teams = reviewers.filter((reviewer) => reviewer.type === "team").map((reviewer) => reviewer.name);
+ const users = reviewers.filter((reviewer) => reviewer.type === "user").map((reviewer) => reviewer.name);
+ if (teams.length === 0 && users.length === 0) {
+ return undefined;
+ }
+ return {
+ ...(teams.length > 0 ? { teams } : {}),
+ ...(users.length > 0 ? { users } : {})
+ };
+}
+
+interface FernSdkGenApiPublicationMapping {
+ package?: FernSdkGenApiPackageConfig;
+ publish: FernSdkGenApiPublishConfig;
+}
+
+function mapPublishOutputV2(publish: FernFiddle.PublishOutputModeV2): FernSdkGenApiPublicationMapping {
+ switch (publish.type) {
+ case "npmOverride":
+ return mapNpmPublish(publish.npmOverride);
+ case "mavenOverride":
+ return mapMavenPublish(publish.mavenOverride);
+ case "pypiOverride":
+ return mapPypiPublish(publish.pypiOverride);
+ case "rubyGemsOverride":
+ return mapNamedPublish("rubygems", publish.rubyGemsOverride);
+ case "nugetOverride":
+ return mapNamedPublish("nuget", publish.nugetOverride);
+ case "cratesOverride":
+ return mapNamedPublish("crates", publish.cratesOverride);
+ case "postman":
+ throw new Error("sdk-gen-api does not support Postman collection publication as an SDK output");
+ }
+}
+
+function mapGithubPublishInfo(publish: FernFiddle.GithubPublishInfo): FernSdkGenApiPublicationMapping {
+ switch (publish.type) {
+ case "npm":
+ return mapNpmPublish(publish);
+ case "maven":
+ return mapMavenPublish(publish);
+ case "pypi":
+ return mapPypiPublish(publish);
+ case "rubygems":
+ return mapNamedPublish("rubygems", publish);
+ case "nuget":
+ return mapNamedPublish("nuget", publish);
+ case "crates":
+ return mapNamedPublish("crates", publish);
+ case "postman":
+ throw new Error("sdk-gen-api does not support Postman collection publication as an SDK output");
+ }
+}
+
+function mapNpmPublish(
+ output: Pick | undefined
+): FernSdkGenApiPublicationMapping {
+ return {
+ ...(output?.packageName ? { package: { packageName: output.packageName } } : {}),
+ publish: {
+ registry: "npm",
+ ...(output?.registryUrl ? { url: output.registryUrl } : {})
+ }
+ };
+}
+
+function mapPypiPublish(
+ output:
+ | Pick
+ | Pick
+ | undefined
+): FernSdkGenApiPublicationMapping {
+ const packageName = output != null && "coordinate" in output ? output.coordinate : output?.packageName;
+ return {
+ ...(packageName ? { package: { packageName } } : {}),
+ publish: {
+ registry: "pypi",
+ ...(output?.registryUrl ? { url: output.registryUrl } : {})
+ }
+ };
+}
+
+function mapMavenPublish(
+ output: Pick | undefined
+): FernSdkGenApiPublicationMapping {
+ const packageConfig = output?.coordinate != null ? packageFromMavenCoordinate(output.coordinate) : undefined;
+ return {
+ ...(packageConfig != null ? { package: packageConfig } : {}),
+ publish: {
+ registry: "maven",
+ ...(output?.registryUrl ? { url: output.registryUrl } : {})
+ }
+ };
+}
+
+function mapNamedPublish(
+ registry: "nuget" | "rubygems" | "crates",
+ output: { registryUrl: string; packageName: string } | undefined
+): FernSdkGenApiPublicationMapping {
+ return {
+ ...(output?.packageName ? { package: { packageName: output.packageName } } : {}),
+ publish: {
+ registry,
+ ...(output?.registryUrl ? { url: output.registryUrl } : {})
+ }
+ };
+}
+
+function packageFromMavenCoordinate(coordinate: string): FernSdkGenApiPackageConfig {
+ const [groupId, artifactId] = coordinate.split(":");
+ if (!groupId || !artifactId) {
+ throw new Error(`Invalid Maven coordinate for sdk-gen-api: ${coordinate}`);
+ }
+ return { groupId, artifactId };
+}
+
+function mapLegacyPublishOutput(
+ generatorInvocation: generatorsYml.GeneratorInvocation,
+ overrides: FernFiddle.RegistryOverrides
+): FernSdkGenApiPublicationMapping {
+ const language = getFernSdkGenApiLanguage(generatorInvocation.name);
+ if (language === "typescript" && overrides.npm != null) {
+ return mapNpmPublish(overrides.npm);
+ }
+ if ((language === "java" || language === "kotlin") && overrides.maven != null) {
+ return mapMavenPublish(overrides.maven);
+ }
+ const registry = defaultPublishRegistry(language);
+ if (registry == null) {
+ throw new Error(`sdk-gen-api cannot infer a registry for ${language ?? generatorInvocation.name}`);
+ }
+ return { publish: { registry } };
+}
+
+function defaultPublishRegistry(language: FernSdkGenApiLanguage | undefined): FernSdkGenApiPublishRegistry | undefined {
+ switch (language) {
+ case "typescript":
+ return "npm";
+ case "python":
+ return "pypi";
+ case "java":
+ case "kotlin":
+ return "maven";
+ case "go":
+ return "go";
+ case "csharp":
+ return "nuget";
+ case "php":
+ return "composer";
+ case "ruby":
+ return "rubygems";
+ case "rust":
+ return "crates";
+ case "swift":
+ case "cli":
+ case undefined:
+ return undefined;
+ }
+}
+
+export interface FernSdkGenApiCandidate {
+ generatorInvocation: generatorsYml.GeneratorInvocation;
+ sdkVersion: string | undefined;
+ specsTarGzBuffer: Buffer | undefined;
+ whitelabel?: FernFiddle.WhitelabelConfig;
+}
+
+export interface EligibleFernSdkGenApiCandidate extends FernSdkGenApiCandidate {
+ sdkVersion: string;
+ specsTarGzBuffer: Buffer;
+}
+
+export function isEligibleForFernSdkGenApi(
+ candidate: FernSdkGenApiCandidate
+): candidate is EligibleFernSdkGenApiCandidate {
+ const { generatorInvocation, sdkVersion, specsTarGzBuffer, whitelabel } = candidate;
+ const language = getFernSdkGenApiLanguage(generatorInvocation.name);
+ // Fiddle currently replaces AUTO after generation. Until that step moves into the shared
+ // pipeline, forwarding AUTO would write the literal placeholder into generated packages.
+ const hasConcreteVersion = sdkVersion != null && sdkVersion.trim().length > 0 && !isAutoVersion(sdkVersion);
+ return (
+ language != null &&
+ (generatorInvocation.language == null || generatorInvocation.language === language) &&
+ hasConcreteVersion &&
+ specsTarGzBuffer != null &&
+ whitelabel == null
+ );
+}
+
+export interface FernSdkGenApiBuildParameters {
+ apiName: string;
+ organization: string;
+ cliVersion: string | undefined;
+ generatorInvocation: generatorsYml.GeneratorInvocation;
+ sdkVersion: string;
+ token: FernToken;
+ specsTarGzBuffer: Buffer;
+ absolutePathToPreview: AbsoluteFilePath | undefined;
+ context: InteractiveTaskContext;
+ targetIdSeed?: string;
+ audiences?: string[];
+ skipFernignore?: boolean;
+}
+
+export interface FernSdkGenApiBuildResponse {
+ createdSnippets: false;
+ snippetsS3PreSignedReadUrl: undefined;
+ actualVersion: string;
+ pullRequestUrl: undefined;
+ noChangesDetected: undefined;
+ publishTarget: undefined;
+}
+
+interface FernSdkGenApiBatchParticipant extends FernSdkGenApiBuildParameters {
+ resolve: (response: FernSdkGenApiBuildResponse) => void;
+ reject: (error: unknown) => void;
+}
+
+/**
+ * Coordinates the generators in one Fern group so they remain one multi-target backend build.
+ * Each generator keeps its own task context and output directory, while submission and polling
+ * happen once for the group.
+ */
+export class FernSdkGenApiBatch {
+ private expectedTargets: number;
+ private readonly participants: FernSdkGenApiBatchParticipant[] = [];
+ private terminalError: unknown;
+ private dispatched = false;
+
+ public constructor(expectedTargets: number) {
+ if (expectedTargets < 1) {
+ throw new Error("A Fern sdk-gen-api batch must expect at least one target");
+ }
+ this.expectedTargets = expectedTargets;
+ }
+
+ public run(parameters: FernSdkGenApiBuildParameters): Promise {
+ if (this.terminalError != null) {
+ return Promise.reject(this.terminalError);
+ }
+ if (this.dispatched) {
+ return Promise.reject(new Error("The Fern sdk-gen-api batch was already dispatched"));
+ }
+ return new Promise((resolve, reject) => {
+ this.participants.push({ ...parameters, resolve, reject });
+ this.dispatchIfReady();
+ });
+ }
+
+ /** Removes a statically selected target that became ineligible after SDK-version/source resolution. */
+ public skip(): void {
+ if (this.dispatched || this.terminalError != null) {
+ return;
+ }
+ this.expectedTargets -= 1;
+ this.dispatchIfReady();
+ }
+
+ /** Prevents siblings waiting at the batch barrier from hanging if preparation of one fails. */
+ public cancel(error: unknown): void {
+ if (this.dispatched || this.terminalError != null) {
+ return;
+ }
+ this.terminalError = error;
+ for (const participant of this.participants) {
+ participant.reject(error);
+ }
+ }
+
+ private dispatchIfReady(): void {
+ if (this.dispatched || this.terminalError != null || this.participants.length !== this.expectedTargets) {
+ return;
+ }
+ this.dispatched = true;
+ void this.dispatch();
+ }
+
+ private async dispatch(): Promise {
+ try {
+ const results = await executeFernSdkGenApiBuild(this.participants);
+ results.forEach((result, index) => {
+ const participant = this.participants[index];
+ if (result.status === "fulfilled") {
+ participant?.resolve(result.value);
+ } else {
+ participant?.reject(result.reason);
+ }
+ });
+ } catch (error) {
+ this.terminalError = error;
+ for (const participant of this.participants) {
+ participant.reject(error);
+ }
+ }
+ }
+}
+
+export async function runFernSdkGenApiBuild(
+ parameters: FernSdkGenApiBuildParameters
+): Promise {
+ const [result] = await executeFernSdkGenApiBuild([parameters]);
+ if (result?.status === "fulfilled") {
+ return result.value;
+ }
+ throw result?.reason ?? new Error("sdk-gen-api did not return the requested target");
+}
+
+async function executeFernSdkGenApiBuild(
+ participants: FernSdkGenApiBuildParameters[]
+): Promise[]> {
+ const first = participants[0];
+ if (first == null) {
+ throw new Error("Cannot submit an empty Fern sdk-gen-api build");
+ }
+ let origin: string | undefined;
+ try {
+ origin = getFernSdkGenApiOrigin();
+ } catch (error) {
+ return first.context.failAndThrow(
+ error instanceof Error ? error.message : "Invalid sdk-gen-api origin",
+ error,
+ {
+ code: CliError.Code.ConfigError
+ }
+ );
+ }
+ if (!origin) {
+ return first.context.failAndThrow(
+ "FERN_SDK_GEN_API_ORIGIN is required when FERN_USE_SDK_GEN_API=true",
+ undefined,
+ { code: CliError.Code.ConfigError }
+ );
+ }
+
+ assertSameBatchInput(participants);
+ const request = createFernSdkGenApiBatchRequest({
+ apiName: first.apiName,
+ organization: first.organization,
+ cliVersion: first.cliVersion,
+ specsTarGzBuffer: first.specsTarGzBuffer,
+ targets: participants.map((participant) => ({
+ generatorInvocation: participant.generatorInvocation,
+ sdkVersion: participant.sdkVersion,
+ targetIdSeed: participant.targetIdSeed,
+ audiences: participant.audiences
+ }))
+ });
+
+ const form = new FormData();
+ form.append("request", JSON.stringify(request));
+ form.append("sources", first.specsTarGzBuffer, {
+ filename: "specs.tar.gz",
+ contentType: "application/gzip"
+ });
+
+ let buildId: string;
+ try {
+ const response = await axios.post<{ buildId: string }>(`${origin}/v1/fern/build`, form, {
+ headers: {
+ ...form.getHeaders(),
+ // TODO: Replace the reusable Fern bearer token with a short-lived, audience-restricted
+ // sdk-generation token once cross-service token exchange is available.
+ Authorization: `Bearer ${first.token.value}`,
+ "X-Fern-Organization-Id": first.organization
+ },
+ maxBodyLength: 30 * 1024 * 1024,
+ timeout: REQUEST_TIMEOUT_MS
+ });
+ buildId = response.data.buildId;
+ } catch (error) {
+ const axiosError = error as AxiosError<{ message?: string }>;
+ return first.context.failAndThrow(
+ `Failed to submit sdk-gen-api build: ${axiosError.response?.data?.message ?? axiosError.message}`,
+ error,
+ { code: CliError.Code.NetworkError }
+ );
+ }
+
+ for (const participant of participants) {
+ participant.context.logger.debug(`sdk-gen-api build ID: ${buildId}`);
+ }
+ const loggedByTarget = new Map();
+ const pollDeadline = Date.now() + POLL_TIMEOUT_MS;
+ for (;;) {
+ let status: FernBuildStatus;
+ try {
+ const response = await axios.get(`${origin}/v1/fern/build/${buildId}`, {
+ headers: {
+ Authorization: `Bearer ${first.token.value}`,
+ "X-Fern-Organization-Id": first.organization
+ },
+ timeout: REQUEST_TIMEOUT_MS
+ });
+ status = response.data;
+ } catch (error) {
+ return first.context.failAndThrow("Failed to poll sdk-gen-api build", error, {
+ code: CliError.Code.NetworkError
+ });
+ }
+
+ const missingTarget = request.targets.find(
+ (requestTarget) => !status.targets.some((target) => target.targetId === requestTarget.targetId)
+ );
+ if (missingTarget != null) {
+ return first.context.failAndThrow(
+ `sdk-gen-api response did not contain target ${missingTarget.targetId}`,
+ undefined,
+ { code: CliError.Code.InternalError }
+ );
+ }
+
+ for (const [index, requestTarget] of request.targets.entries()) {
+ const target = status.targets.find((candidate) => candidate.targetId === requestTarget.targetId);
+ const context = participants[index]?.context;
+ if (target == null || context == null) {
+ continue;
+ }
+ const logged = loggedByTarget.get(target.targetId) ?? 0;
+ for (const log of target.logs.slice(logged)) {
+ context.logger.info(log.message);
+ }
+ loggedByTarget.set(target.targetId, target.logs.length);
+ }
+
+ const allTargetsTerminal = request.targets.every((requestTarget) => isTerminal(status, requestTarget.targetId));
+ if (allTargetsTerminal || status.status === "failed" || status.status === "succeeded") {
+ return Promise.allSettled(
+ participants.map((participant, index) =>
+ finishFernSdkGenApiTarget(participant, request.targets[index]?.targetId, status)
+ )
+ );
+ }
+ if (Date.now() >= pollDeadline) {
+ return first.context.failAndThrow(
+ `Timed out waiting for sdk-gen-api build ${buildId} after ${POLL_TIMEOUT_MS / 60_000} minutes`,
+ undefined,
+ { code: CliError.Code.NetworkError }
+ );
+ }
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
+ }
+}
+
+function isTerminal(status: FernBuildStatus, targetId: string): boolean {
+ const target = status.targets.find((candidate) => candidate.targetId === targetId);
+ return target?.status === "failed" || target?.status === "succeeded";
+}
+
+async function finishFernSdkGenApiTarget(
+ participant: FernSdkGenApiBuildParameters,
+ targetId: string | undefined,
+ status: FernBuildStatus
+): Promise {
+ const target = status.targets.find((candidate) => candidate.targetId === targetId);
+ if (target == null) {
+ return participant.context.failAndThrow(
+ "sdk-gen-api response did not contain the requested target",
+ undefined,
+ {
+ code: CliError.Code.InternalError
+ }
+ );
+ }
+ if (target.status === "failed") {
+ return participant.context.failAndThrow(target.error?.message ?? "sdk-gen-api generation failed", undefined, {
+ code: CliError.Code.ContainerError
+ });
+ }
+ if (target.status !== "succeeded") {
+ return participant.context.failAndThrow(
+ `sdk-gen-api build ended with status ${status.status} while target ${target.targetId} remained ${target.status}`,
+ undefined,
+ { code: CliError.Code.InternalError }
+ );
+ }
+ if (target.result?.artifactUrl == null) {
+ return participant.context.failAndThrow("sdk-gen-api target completed without an artifact URL", undefined, {
+ code: CliError.Code.InternalError
+ });
+ }
+ const outputPath =
+ participant.absolutePathToPreview != null
+ ? join(
+ participant.absolutePathToPreview,
+ RelativeFilePath.of(path.basename(participant.generatorInvocation.name))
+ )
+ : participant.generatorInvocation.absolutePathToLocalOutput;
+ if (outputPath != null) {
+ await downloadFilesForTask({
+ s3PreSignedReadUrl: target.result.artifactUrl,
+ absolutePathToLocalOutput: outputPath,
+ context: participant.context,
+ skipFernignore: participant.skipFernignore
+ });
+ }
+ return {
+ createdSnippets: false,
+ snippetsS3PreSignedReadUrl: undefined,
+ actualVersion: target.result.actualVersion ?? participant.sdkVersion,
+ pullRequestUrl: undefined,
+ noChangesDetected: undefined,
+ publishTarget: undefined
+ };
+}
+
+function assertSameBatchInput(participants: FernSdkGenApiBuildParameters[]): void {
+ const first = participants[0];
+ if (first == null) {
+ return;
+ }
+ const sourceHash = createHash("sha256").update(first.specsTarGzBuffer).digest("hex");
+ for (const participant of participants.slice(1)) {
+ const participantSourceHash = createHash("sha256").update(participant.specsTarGzBuffer).digest("hex");
+ if (
+ participant.apiName !== first.apiName ||
+ participant.organization !== first.organization ||
+ participant.token.value !== first.token.value ||
+ participantSourceHash !== sourceHash
+ ) {
+ throw new Error("Fern sdk-gen-api batch targets must share API, organization, token, and sources");
+ }
+ }
+}
+
+export function createFernSdkGenApiRequest({
+ apiName,
+ organization,
+ cliVersion,
+ generatorInvocation,
+ sdkVersion,
+ specsTarGzBuffer
+}: {
+ apiName: string;
+ organization: string;
+ cliVersion: string | undefined;
+ generatorInvocation: generatorsYml.GeneratorInvocation;
+ sdkVersion: string;
+ specsTarGzBuffer: Buffer;
+}): FernSdkGenApiRequest {
+ return createFernSdkGenApiBatchRequest({
+ apiName,
+ organization,
+ cliVersion,
+ specsTarGzBuffer,
+ targets: [{ generatorInvocation, sdkVersion }]
+ });
+}
+
+export function createFernSdkGenApiBatchRequest({
+ apiName,
+ organization,
+ cliVersion,
+ specsTarGzBuffer,
+ targets
+}: {
+ apiName: string;
+ organization: string;
+ cliVersion: string | undefined;
+ specsTarGzBuffer: Buffer;
+ targets: Array<{
+ generatorInvocation: generatorsYml.GeneratorInvocation;
+ sdkVersion: string;
+ targetIdSeed?: string;
+ audiences?: string[];
+ }>;
+}): FernSdkGenApiRequest {
+ if (targets.length === 0) {
+ throw new Error("Cannot create an empty Fern sdk-gen-api request");
+ }
+ const requestTargets = targets.map(({ generatorInvocation, sdkVersion, targetIdSeed, audiences }, index) => {
+ const language = getFernSdkGenApiLanguage(generatorInvocation.name);
+ if (language == null) {
+ throw new Error(`Unsupported Fern SDK generator: ${generatorInvocation.name}`);
+ }
+ const output = mapFernSdkGenApiOutput(generatorInvocation);
+ const targetId = createHash("sha256")
+ .update(
+ `${apiName}:${generatorInvocation.name}:${generatorInvocation.version}:${targetIdSeed ?? index.toString()}`
+ )
+ .digest("hex")
+ .slice(0, 20);
+ return {
+ targetId,
+ apiInputId: "default",
+ language,
+ sdk: { name: apiName, version: sdkVersion },
+ fernGenerator: {
+ id: generatorInvocation.name,
+ version: generatorInvocation.version
+ },
+ ...(output.package != null ? { package: output.package } : {}),
+ invocation: {
+ customConfig: (stripCliConfigKeys(generatorInvocation.config) ?? {}) as Record,
+ keywords: generatorInvocation.keywords ?? [],
+ smartCasing: generatorInvocation.smartCasing,
+ smartCasingDigitWordBoundary: generatorInvocation.smartCasingDigitWordBoundary,
+ disableExamples: generatorInvocation.disableExamples,
+ ...(audiences != null ? { audiences } : {}),
+ ...(generatorInvocation.readme != null
+ ? { readme: generatorInvocation.readme as Record }
+ : {}),
+ ...(generatorInvocation.settings != null
+ ? {
+ settings: generatorInvocation.settings as Record
+ }
+ : {}),
+ ...(generatorInvocation.apiOverride != null
+ ? {
+ apiOverride: generatorInvocation.apiOverride as Record
+ }
+ : {})
+ },
+ requestedOutput: output.requestedOutput
+ };
+ });
+ const apiInputs: FernSdkGenApiRequest["apiInputs"] = [{ id: "default", specIndexes: "all" }];
+ const idempotencyKey = createHash("sha256")
+ .update(specsTarGzBuffer)
+ .update(
+ JSON.stringify({
+ protocolVersion: 1,
+ organization,
+ apiName,
+ apiInputs,
+ targets: requestTargets
+ })
+ )
+ .digest("hex");
+
+ return {
+ protocolVersion: 1,
+ apiName,
+ ...(cliVersion ? { cliVersion } : {}),
+ idempotencyKey,
+ apiInputs,
+ targets: requestTargets
+ };
+}
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts
index 9a28538e5208..f75914b7c7ab 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/index.ts
@@ -1,4 +1,5 @@
export { findGeneratorLineNumber, GeneratorOccurrenceTracker, getOutputRepoUrl } from "./automationMetadata.js";
+export { getFernSdkGenApiLanguage, isFernSdkGenApiEnabled } from "./fernSdkGenApi.js";
export { getDynamicGeneratorConfig } from "./getDynamicGeneratorConfig.js";
export type { PublishTarget } from "./publishTarget.js";
export { extractPublishTarget } from "./publishTarget.js";
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts
index e7f352143070..9faa710f9af5 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForAPIWorkspace.ts
@@ -15,6 +15,7 @@ import { appendFile } from "fs/promises";
import { findGeneratorLineNumber, GeneratorOccurrenceTracker, getOutputRepoUrl } from "./automationMetadata.js";
import { downloadSnippetsForTask } from "./downloadSnippetsForTask.js";
+import { FernSdkGenApiBatch, getFernSdkGenApiLanguage, isFernSdkGenApiEnabled } from "./fernSdkGenApi.js";
import type { PublishTarget } from "./publishTarget.js";
import type { AutomationRunOptions } from "./RemoteGeneratorRunRecorder.js";
import { resolveAutoDiscoveredFernignorePath } from "./resolveAutoDiscoveredFernignorePath.js";
@@ -143,9 +144,18 @@ export async function runRemoteGenerationForAPIWorkspace({
effectiveOccurrenceTracker.recordOccurrences(generatorGroup.generators);
}
const generatorsYmlAbsolutePath = workspace.generatorsConfiguration?.absolutePathToConfiguration;
+ const sdkGenApiCandidateIndexes = new Set(
+ isFernSdkGenApiEnabled()
+ ? generatorGroup.generators.flatMap((generator, index) =>
+ getFernSdkGenApiLanguage(generator.name) != null ? [index] : []
+ )
+ : []
+ );
+ const sdkGenApiBatch =
+ sdkGenApiCandidateIndexes.size > 1 ? new FernSdkGenApiBatch(sdkGenApiCandidateIndexes.size) : undefined;
const results = await Promise.all(
- generatorGroup.generators.map((generatorInvocation) =>
+ generatorGroup.generators.map((generatorInvocation, generatorIndex) =>
context.runInteractiveTask({ name: generatorInvocation.name }, (interactiveTaskContext) =>
generateOne({
generatorInvocation,
@@ -183,6 +193,8 @@ export async function runRemoteGenerationForAPIWorkspace({
occurrenceTracker: effectiveOccurrenceTracker,
loginCommand,
getSpecsTarGzBuffer,
+ sdkGenApiBatch: sdkGenApiCandidateIndexes.has(generatorIndex) ? sdkGenApiBatch : undefined,
+ sdkGenApiTargetIdSeed: generatorIndex.toString(),
generateFullProject,
onSnippetsProduced: (invocation) => snippetsProducedBy.push(invocation)
})
@@ -242,6 +254,8 @@ async function generateOne({
occurrenceTracker,
loginCommand,
getSpecsTarGzBuffer,
+ sdkGenApiBatch,
+ sdkGenApiTargetIdSeed,
generateFullProject,
onSnippetsProduced
}: {
@@ -279,6 +293,8 @@ async function generateOne({
occurrenceTracker: GeneratorOccurrenceTracker;
loginCommand: string | undefined;
getSpecsTarGzBuffer: ((generatorName: string) => Promise) | undefined;
+ sdkGenApiBatch: FernSdkGenApiBatch | undefined;
+ sdkGenApiTargetIdSeed: string;
generateFullProject: boolean | undefined;
/** Invoked post-success when the generator produced snippets. */
onSnippetsProduced: (invocation: generatorsYml.GeneratorInvocation) => void;
@@ -365,6 +381,8 @@ async function generateOne({
disableTelemetry,
loginCommand,
specsTarGzBuffer: await getSpecsTarGzBuffer?.(generatorInvocation.name),
+ sdkGenApiBatch,
+ sdkGenApiTargetIdSeed,
generateFullProject
});
@@ -418,6 +436,7 @@ async function generateOne({
isAutomation: automation != null
});
} catch (error) {
+ sdkGenApiBatch?.cancel(error);
if (automation == null) {
throw error;
}
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts
index 5bc7483997af..2e3ca4497e8c 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForGenerator.ts
@@ -32,6 +32,13 @@ import { CliError, InteractiveTaskContext } from "@fern-api/task-context";
import { FernWorkspace, IdentifiableSource } from "@fern-api/workspace-loader";
import { FernFiddle } from "@fern-fern/fiddle-sdk";
import { createAndStartJob } from "./createAndStartJob.js";
+import {
+ FernSdkGenApiBatch,
+ getFernSdkGenApiLanguage,
+ isEligibleForFernSdkGenApi,
+ isFernSdkGenApiEnabled,
+ runFernSdkGenApiBuild
+} from "./fernSdkGenApi.js";
import { getDynamicGeneratorConfig } from "./getDynamicGeneratorConfig.js";
import { pollJobAndReportStatus } from "./pollJobAndReportStatus.js";
import { RemoteTaskHandler } from "./RemoteTaskHandler.js";
@@ -68,6 +75,8 @@ export async function runRemoteGenerationForGenerator({
disableTelemetry,
loginCommand,
specsTarGzBuffer,
+ sdkGenApiBatch,
+ sdkGenApiTargetIdSeed,
generateFullProject
}: {
projectConfig: fernConfigJson.ProjectConfig;
@@ -118,6 +127,8 @@ export async function runRemoteGenerationForGenerator({
*/
loginCommand?: string;
specsTarGzBuffer?: Buffer;
+ sdkGenApiBatch?: FernSdkGenApiBatch;
+ sdkGenApiTargetIdSeed?: string;
/**
* When true, filesystem (local-file-system / download) outputs are generated as full,
* packageable projects (pyproject.toml, README.md, etc.) instead of source-only output.
@@ -354,81 +365,148 @@ export async function runRemoteGenerationForGenerator({
};
}
- const job = await createAndStartJob({
- projectConfig,
- workspace,
- organization,
- generatorInvocation: generatorInvocationWithEnvVarSubstitutions,
- context: interactiveTaskContext,
- version: resolvedVersion,
- intermediateRepresentation: {
- ...ir,
- fdrApiDefinitionId,
- publishConfig: getPublishConfig({
- generatorInvocation: generatorInvocationWithEnvVarSubstitutions,
- version: resolvedVersion,
- userProvidedVersion: version,
- packageName,
- selfHosted: ir.selfHosted ?? false,
- generateFullProject,
- context: interactiveTaskContext
- })
- },
- shouldLogS3Url,
- token,
- whitelabel: whitelabel != null ? substituteEnvVars(whitelabel) : undefined,
- replay,
- irVersionOverride,
- absolutePathToPreview,
- fiddlePreview,
- pushPreviewBranch,
- fernignorePath,
- skipFernignore,
- retryRateLimited,
- automationMode,
- autoMerge,
- skipIfNoDiff,
- verify,
- loginCommand,
- specsTarGzBuffer
- });
- interactiveTaskContext.logger.debug(`Job ID: ${job.jobId}`);
+ let result: RemoteTaskHandler.Response | undefined;
+ let usedSdkGenApi = false;
+ const sdkGenApiEnabled = isFernSdkGenApiEnabled();
+ const sdkGenApiLanguage = getFernSdkGenApiLanguage(generatorInvocationWithEnvVarSubstitutions.name);
+ if (sdkGenApiEnabled && sdkGenApiLanguage != null) {
+ if (replay?.enabled === true) {
+ return interactiveTaskContext.failAndThrow("sdk-gen-api does not yet support replay", undefined, {
+ code: CliError.Code.ConfigError
+ });
+ }
+ if (generateFullProject === true) {
+ return interactiveTaskContext.failAndThrow(
+ "sdk-gen-api does not yet support full-project generation",
+ undefined,
+ { code: CliError.Code.ConfigError }
+ );
+ }
+ const candidate = {
+ generatorInvocation: generatorInvocationWithEnvVarSubstitutions,
+ sdkVersion: resolvedVersion,
+ specsTarGzBuffer,
+ whitelabel
+ };
+ if (!isEligibleForFernSdkGenApi(candidate)) {
+ const reason =
+ resolvedVersion == null
+ ? "the SDK version could not be resolved"
+ : isAutoVersion(resolvedVersion)
+ ? "automatic SDK versioning has not yet moved from Fiddle to the shared pipeline"
+ : whitelabel != null
+ ? "whitelabel generation has not yet moved from Fiddle to the shared pipeline"
+ : specsTarGzBuffer == null
+ ? "the source archive is unavailable"
+ : `generator language ${generatorInvocationWithEnvVarSubstitutions.language ?? "unknown"} does not match ${sdkGenApiLanguage}`;
+ return interactiveTaskContext.failAndThrow(
+ `Cannot submit SDK generation to sdk-gen-api: ${reason}`,
+ undefined,
+ {
+ code: CliError.Code.ConfigError
+ }
+ );
+ }
+ if (verify === true) {
+ interactiveTaskContext.logger.warn("sdk-gen-api does not yet run Fern's post-generation verification step");
+ }
+ const parameters = {
+ apiName: getOriginalName(ir.apiName),
+ organization,
+ cliVersion: workspace.cliVersion,
+ generatorInvocation: candidate.generatorInvocation,
+ sdkVersion: candidate.sdkVersion,
+ token,
+ specsTarGzBuffer: candidate.specsTarGzBuffer,
+ absolutePathToPreview,
+ context: interactiveTaskContext,
+ targetIdSeed: sdkGenApiTargetIdSeed,
+ audiences: audiences.type === "select" ? audiences.audiences : undefined,
+ skipFernignore
+ };
+ result = await (sdkGenApiBatch?.run(parameters) ?? runFernSdkGenApiBuild(parameters));
+ usedSdkGenApi = true;
+ } else {
+ sdkGenApiBatch?.skip();
+ }
- const taskId = job.taskIds[0];
- if (taskId == null) {
- interactiveTaskContext.failAndThrow("Did not receive a task ID.", undefined, {
- code: CliError.Code.NetworkError
+ if (!usedSdkGenApi) {
+ const job = await createAndStartJob({
+ projectConfig,
+ workspace,
+ organization,
+ generatorInvocation: generatorInvocationWithEnvVarSubstitutions,
+ context: interactiveTaskContext,
+ version: resolvedVersion,
+ intermediateRepresentation: {
+ ...ir,
+ fdrApiDefinitionId,
+ publishConfig: getPublishConfig({
+ generatorInvocation: generatorInvocationWithEnvVarSubstitutions,
+ version: resolvedVersion,
+ userProvidedVersion: version,
+ packageName,
+ selfHosted: ir.selfHosted ?? false,
+ generateFullProject,
+ context: interactiveTaskContext
+ })
+ },
+ shouldLogS3Url,
+ token,
+ whitelabel: whitelabel != null ? substituteEnvVars(whitelabel) : undefined,
+ replay,
+ irVersionOverride,
+ absolutePathToPreview,
+ fiddlePreview,
+ pushPreviewBranch,
+ fernignorePath,
+ skipFernignore,
+ retryRateLimited,
+ automationMode,
+ autoMerge,
+ skipIfNoDiff,
+ verify,
+ loginCommand,
+ specsTarGzBuffer
});
- return undefined;
- }
- interactiveTaskContext.logger.debug(`Task ID: ${taskId}`);
-
- const taskHandler = new RemoteTaskHandler({
- job,
- taskId,
- generatorInvocation,
- interactiveTaskContext,
- absolutePathToPreview,
- telemetryContext: {
- cliVersion: workspace.cliVersion,
- orgId: projectConfig.organization,
- automationMode: automationMode === true,
- autoMerge: autoMerge === true,
- skipIfNoDiff: skipIfNoDiff === true,
- versionArg: version == null ? "none" : isAutoVersion(version) ? "auto" : "explicit",
- versionBump: undefined,
- replayConfigEnabled: replay?.enabled === true,
- noReplayFlag: noReplay === true,
- disableTelemetry: disableTelemetry === true
+ interactiveTaskContext.logger.debug(`Job ID: ${job.jobId}`);
+
+ const taskId = job.taskIds[0];
+ if (taskId == null) {
+ interactiveTaskContext.failAndThrow("Did not receive a task ID.", undefined, {
+ code: CliError.Code.NetworkError
+ });
+ return undefined;
}
- });
+ interactiveTaskContext.logger.debug(`Task ID: ${taskId}`);
+
+ const taskHandler = new RemoteTaskHandler({
+ job,
+ taskId,
+ generatorInvocation,
+ interactiveTaskContext,
+ absolutePathToPreview,
+ telemetryContext: {
+ cliVersion: workspace.cliVersion,
+ orgId: projectConfig.organization,
+ automationMode: automationMode === true,
+ autoMerge: autoMerge === true,
+ skipIfNoDiff: skipIfNoDiff === true,
+ versionArg: version == null ? "none" : isAutoVersion(version) ? "auto" : "explicit",
+ versionBump: undefined,
+ replayConfigEnabled: replay?.enabled === true,
+ noReplayFlag: noReplay === true,
+ disableTelemetry: disableTelemetry === true
+ }
+ });
- let result = await pollJobAndReportStatus({
- job,
- taskHandler,
- taskId,
- context: interactiveTaskContext
- });
+ result = await pollJobAndReportStatus({
+ job,
+ taskHandler,
+ taskId,
+ context: interactiveTaskContext
+ });
+ }
// Fall back to the locally-resolved version when Fiddle doesn't echo it back
// (e.g. GitHub push modes where no registry publish or release tag occurs).
diff --git a/packages/generator-cli/changes/0.9.55/fix-empty-readme-requirements.yml b/packages/generator-cli/changes/0.9.55/fix-empty-readme-requirements.yml
new file mode 100644
index 000000000000..7f1f8dadb044
--- /dev/null
+++ b/packages/generator-cli/changes/0.9.55/fix-empty-readme-requirements.yml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../fern-changes-yml.schema.json
+
+- summary: |
+ The README's `## Requirements` section is now omitted when the generator
+ supplies an empty requirements list, instead of rendering a heading followed by
+ a dangling "This SDK requires:" line.
+ type: fix
diff --git a/packages/generator-cli/src/readme/ReadmeGenerator.ts b/packages/generator-cli/src/readme/ReadmeGenerator.ts
index 017ad556896a..66fe14dcbc9f 100644
--- a/packages/generator-cli/src/readme/ReadmeGenerator.ts
+++ b/packages/generator-cli/src/readme/ReadmeGenerator.ts
@@ -76,7 +76,7 @@ export class ReadmeGenerator {
})
);
}
- if (this.readmeConfig.requirements != null) {
+ if (this.readmeConfig.requirements != null && this.readmeConfig.requirements.length > 0) {
blocks.push(
await this.generateRequirements({
requirements: this.readmeConfig.requirements
diff --git a/packages/generator-cli/versions.yml b/packages/generator-cli/versions.yml
index e3bac177f4ba..d5235b91fc1f 100644
--- a/packages/generator-cli/versions.yml
+++ b/packages/generator-cli/versions.yml
@@ -1,4 +1,12 @@
# yaml-language-server: $schema=../../versions-yml.schema.json
+- version: 0.9.55
+ changelogEntry:
+ - summary: |
+ The README's `## Requirements` section is now omitted when the generator
+ supplies an empty requirements list, instead of rendering a heading followed by
+ a dangling "This SDK requires:" line.
+ type: fix
+ createdAt: "2026-08-20"
- version: 0.9.54
changelogEntry:
- summary: |
diff --git a/seed/csharp-sdk/accept-header/README.md b/seed/csharp-sdk/accept-header/README.md
index f17383503dbd..32c0b746979c 100644
--- a/seed/csharp-sdk/accept-header/README.md
+++ b/seed/csharp-sdk/accept-header/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.EndpointAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.EndpointAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.EndpointAsync(...);
+var parsedData = await client.Service.EndpointAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs
index 3c7977535966..6966d7c112f0 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs
index 5fc79d21493f..620b5d67a33f 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs
index 28b5ca870266..0088859e9b13 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAccept.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAccept.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs
index c184c18ebc7f..6383bf8dd9ef 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs
index feb17b29e6c3..c683ad5b7771 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAccept.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs
index 448ff97a0744..fafefead0ab4 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj b/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj
index 864f3598097e..dd1f4f13a6f1 100644
--- a/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj
+++ b/seed/csharp-sdk/accept-header/src/SeedAccept/SeedAccept.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/accept-header/fern
+ https://github.com/accept-header/fern
+ git
true
diff --git a/seed/csharp-sdk/alias-extends/README.md b/seed/csharp-sdk/alias-extends/README.md
index b0125b789b36..fb34ea5dd4f5 100644
--- a/seed/csharp-sdk/alias-extends/README.md
+++ b/seed/csharp-sdk/alias-extends/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.ExtendedInlineRequestBodyAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.ExtendedInlineRequestBodyAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.ExtendedInlineRequestBodyAsync(...);
+var parsedData = await client.ExtendedInlineRequestBodyAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs
index 66b696dcdbcc..a7e576ca72dd 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs
index ce1b1a20a3dd..0c71f90ef0f7 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs
index ad21e33cbf3e..4b5450e179ca 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAliasExtends.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAliasExtends.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs
index 06dbd0e43ece..0b9758148361 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs
index 2632a45034ab..1ded89db50ec 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAliasExtends.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs
index c3d6fc86da3b..fc8e1861f6ac 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj
index dd5c3d4aee50..d0552c17e36e 100644
--- a/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj
+++ b/seed/csharp-sdk/alias-extends/src/SeedAliasExtends/SeedAliasExtends.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/alias-extends/fern
+ https://github.com/alias-extends/fern
+ git
true
diff --git a/seed/csharp-sdk/alias/README.md b/seed/csharp-sdk/alias/README.md
index 104243ec3ac9..e6ed1038d666 100644
--- a/seed/csharp-sdk/alias/README.md
+++ b/seed/csharp-sdk/alias/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.GetAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.GetAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.GetAsync(...);
+var parsedData = await client.GetAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs
index e91db1abe5f6..b9afc85edb3d 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs
index 2ff74866d9f5..8a768aa2b936 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs
index 9ecd5ff22fea..9a845b375cfb 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAlias.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAlias.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs
index d4e5d898d3a8..d93a572fa7f9 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs
index 68b417382104..792d43bf0aeb 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAlias.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs b/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs
index 0b9c952a047c..164db5d273ed 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/alias/src/SeedAlias/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj b/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj
index d8bf4fe5ab1a..bb549267341d 100644
--- a/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj
+++ b/seed/csharp-sdk/alias/src/SeedAlias/SeedAlias.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/alias/fern
+ https://github.com/alias/fern
+ git
true
diff --git a/seed/csharp-sdk/allof-inline/README.md b/seed/csharp-sdk/allof-inline/README.md
index 838b7416734f..e5c311c96ff8 100644
--- a/seed/csharp-sdk/allof-inline/README.md
+++ b/seed/csharp-sdk/allof-inline/README.md
@@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.CreateRuleAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.CreateRuleAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.CreateRuleAsync(...);
+var parsedData = await client.CreateRuleAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj
index 72bf657a0f91..69c62019e265 100644
--- a/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/allof-inline/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/allof-inline/fern
+ https://github.com/allof-inline/fern
+ git
true
diff --git a/seed/csharp-sdk/allof/README.md b/seed/csharp-sdk/allof/README.md
index 4e07988c7973..0e598aca44da 100644
--- a/seed/csharp-sdk/allof/README.md
+++ b/seed/csharp-sdk/allof/README.md
@@ -26,6 +26,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.CreateRuleAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.CreateRuleAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.CreateRuleAsync(...);
+var parsedData = await client.CreateRuleAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/allof/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj
index f45281f7c5b1..171dfc112dd3 100644
--- a/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/allof/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/allof/fern
+ https://github.com/allof/fern
+ git
true
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/README.md b/seed/csharp-sdk/any-auth/no-custom-config/README.md
index 1fe31e98aa60..90ad0cf01908 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/README.md
+++ b/seed/csharp-sdk/any-auth/no-custom-config/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Auth.GetTokenAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Auth.GetTokenAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Auth.GetTokenAsync(...);
+var parsedData = await client.Auth.GetTokenAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
index b481743b3ae5..8b5797273cd9 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs
index 6e2e34d6d4d6..a7b6539c5f76 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs
index d98ea4ad86dc..83713c9c4a6c 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAnyAuth.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAnyAuth.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs
index ca15336eada1..0c12099c226f 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs
index 01fc91d6636f..3a7e688f98aa 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAnyAuth.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs
index f079a14c6938..63dc4ef7e442 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj
index 33da248f37c5..71d675291ed4 100644
--- a/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj
+++ b/seed/csharp-sdk/any-auth/no-custom-config/src/SeedAnyAuth/SeedAnyAuth.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/any-auth/fern
+ https://github.com/any-auth/fern
+ git
true
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md b/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md
index 1fe31e98aa60..90ad0cf01908 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -109,7 +112,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Auth.GetTokenAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -122,7 +125,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Auth.GetTokenAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -152,7 +155,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Auth.GetTokenAsync(...);
+var parsedData = await client.Auth.GetTokenAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
index b481743b3ae5..8b5797273cd9 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs
index 6e2e34d6d4d6..a7b6539c5f76 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs
index d98ea4ad86dc..83713c9c4a6c 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAnyAuth.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAnyAuth.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs
index ca15336eada1..0c12099c226f 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs
index 01fc91d6636f..3a7e688f98aa 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAnyAuth.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs
index f079a14c6938..63dc4ef7e442 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj
index 33da248f37c5..71d675291ed4 100644
--- a/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj
+++ b/seed/csharp-sdk/any-auth/prefer-explicit-auth/src/SeedAnyAuth/SeedAnyAuth.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/any-auth/fern
+ https://github.com/any-auth/fern
+ git
true
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/README.md b/seed/csharp-sdk/api-wide-base-path-with-default/README.md
index 562a6a80f3ac..93611b6ea44b 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/README.md
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Widgets.CreateAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Widgets.CreateAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Widgets.CreateAsync(...);
+var parsedData = await client.Widgets.CreateAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj
index 501c16187fc6..ceba29f259c3 100644
--- a/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/api-wide-base-path-with-default/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/api-wide-base-path-with-default/fern
+ https://github.com/api-wide-base-path-with-default/fern
+ git
true
diff --git a/seed/csharp-sdk/api-wide-base-path/README.md b/seed/csharp-sdk/api-wide-base-path/README.md
index 1c503d5c9343..e18103460829 100644
--- a/seed/csharp-sdk/api-wide-base-path/README.md
+++ b/seed/csharp-sdk/api-wide-base-path/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.PostAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.PostAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.PostAsync(...);
+var parsedData = await client.Service.PostAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs
index 58a1f2e9f049..197ab07ffefa 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs
index d247aa5e131d..a39a677248fa 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs
index 0b5eab212195..8848f8cdc7c8 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApiWideBasePath.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApiWideBasePath.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs
index e4f242f75502..ae2e14a0fd24 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs
index 93e5cce0086c..681804f39f93 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApiWideBasePath.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs
index aee28fc7568b..b04f1b7c782c 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj
index a37db4f16013..fe24c3169313 100644
--- a/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj
+++ b/seed/csharp-sdk/api-wide-base-path/src/SeedApiWideBasePath/SeedApiWideBasePath.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/api-wide-base-path/fern
+ https://github.com/api-wide-base-path/fern
+ git
true
diff --git a/seed/csharp-sdk/audiences/README.md b/seed/csharp-sdk/audiences/README.md
index e2388d0e53f1..1fc2fb4e1d66 100644
--- a/seed/csharp-sdk/audiences/README.md
+++ b/seed/csharp-sdk/audiences/README.md
@@ -25,6 +25,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -122,7 +125,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Foo.FindAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -135,7 +138,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Foo.FindAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -165,7 +168,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Foo.FindAsync(...);
+var parsedData = await client.Foo.FindAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs
index 067674c0542e..656cfc247e89 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs
index 63b1bfb76838..10ec582111be 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs
index 2761d3bdbc11..3b2f52db0893 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedAudiences.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedAudiences.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs
index cb0d4e88e856..1ad60a4efa91 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs
index 99ef51ffecf3..f7a508561149 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedAudiences.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs
index 51a497140c25..067849d758ea 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj b/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj
index 9e31d759b50e..0e6f28ea5855 100644
--- a/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj
+++ b/seed/csharp-sdk/audiences/src/SeedAudiences/SeedAudiences.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/audiences/fern
+ https://github.com/audiences/fern
+ git
true
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/README.md b/seed/csharp-sdk/basic-auth-environment-variables/README.md
index 8ca7dd80455b..d3a27e918f63 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/README.md
+++ b/seed/csharp-sdk/basic-auth-environment-variables/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.BasicAuth.PostWithBasicAuthAsync(...);
+var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs
index d90b57b63c1f..e063c2f459bc 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs
index 97cd783845d4..c0514cda70b8 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs
index d573fb2ff908..9d0d6e643f48 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBasicAuthEnvironmentVariables.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBasicAuthEnvironmentVariables.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs
index e40284dafe11..12ff55465be8 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs
index e90362425e91..b83c42ffc4e2 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBasicAuthEnvironmentVariables.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs
index e39124fd69a1..f5fb4ce1be0e 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj
index 984b860aec31..762702b8d688 100644
--- a/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj
+++ b/seed/csharp-sdk/basic-auth-environment-variables/src/SeedBasicAuthEnvironmentVariables/SeedBasicAuthEnvironmentVariables.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/basic-auth-environment-variables/fern
+ https://github.com/basic-auth-environment-variables/fern
+ git
true
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/README.md b/seed/csharp-sdk/basic-auth-pw-omitted/README.md
index 43f9872f594f..b8b9f00ca5ac 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/README.md
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.BasicAuth.PostWithBasicAuthAsync(...);
+var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs
index 740e356b0246..297fc8fca69a 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs
index 8361264a88b1..aad9e8ac4e09 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs
index 9355ac14b0df..83710a7c52be 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBasicAuthPwOmitted.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBasicAuthPwOmitted.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs
index f165b4166582..3f26902cdce5 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs
index e5184234617c..e4d5488283b8 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBasicAuthPwOmitted.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs
index bd8ef83e2d7b..7fa2cee42f89 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj
index 659e1108dc6e..0fb5180b72b1 100644
--- a/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj
+++ b/seed/csharp-sdk/basic-auth-pw-omitted/src/SeedBasicAuthPwOmitted/SeedBasicAuthPwOmitted.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/basic-auth-pw-omitted/fern
+ https://github.com/basic-auth-pw-omitted/fern
+ git
true
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/README.md b/seed/csharp-sdk/basic-auth/no-custom-config/README.md
index 30db3ef25cee..975d3c256668 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/README.md
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.BasicAuth.PostWithBasicAuthAsync(...);
+var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
index 529bd5841769..671e3c858c43 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs
index b02b272a7bda..5b1bdb0d7dee 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs
index 7bce298d02f2..b4a967445efb 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs
index f4ea51b459eb..8139e19a956e 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs
index 46a7d5a324c4..ca5a8509e750 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs
index e2ce554def75..3c2e4f0aa7cb 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj
index 0d2301bf46a3..01bfdaecef8e 100644
--- a/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj
+++ b/seed/csharp-sdk/basic-auth/no-custom-config/src/SeedBasicAuth/SeedBasicAuth.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/basic-auth/fern
+ https://github.com/basic-auth/fern
+ git
true
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/README.md b/seed/csharp-sdk/basic-auth/unified-client-options/README.md
index a838c791d1d6..214266c0701d 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/README.md
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -105,7 +108,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -118,7 +121,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -148,7 +151,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.BasicAuth.PostWithBasicAuthAsync(...);
+var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
index 529bd5841769..671e3c858c43 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs
index b02b272a7bda..5b1bdb0d7dee 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs
index 7bce298d02f2..b4a967445efb 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs
index f4ea51b459eb..8139e19a956e 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs
index 46a7d5a324c4..ca5a8509e750 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs
index e2ce554def75..3c2e4f0aa7cb 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj
index 0d2301bf46a3..01bfdaecef8e 100644
--- a/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj
+++ b/seed/csharp-sdk/basic-auth/unified-client-options/src/SeedBasicAuth/SeedBasicAuth.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/basic-auth/fern
+ https://github.com/basic-auth/fern
+ git
true
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/README.md b/seed/csharp-sdk/basic-auth/wire-tests/README.md
index 30db3ef25cee..975d3c256668 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/README.md
+++ b/seed/csharp-sdk/basic-auth/wire-tests/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.BasicAuth.PostWithBasicAuthAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.BasicAuth.PostWithBasicAuthAsync(...);
+var parsedData = await client.BasicAuth.PostWithBasicAuthAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
index 529bd5841769..671e3c858c43 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs
index b02b272a7bda..5b1bdb0d7dee 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs
index 7bce298d02f2..b4a967445efb 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBasicAuth.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs
index f4ea51b459eb..8139e19a956e 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs
index 46a7d5a324c4..ca5a8509e750 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBasicAuth.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs
index e2ce554def75..3c2e4f0aa7cb 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj
index 0d2301bf46a3..01bfdaecef8e 100644
--- a/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj
+++ b/seed/csharp-sdk/basic-auth/wire-tests/src/SeedBasicAuth/SeedBasicAuth.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/basic-auth/fern
+ https://github.com/basic-auth/fern
+ git
true
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md
index 94acfc23b6d5..8a217956432e 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.GetWithBearerTokenAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.GetWithBearerTokenAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.GetWithBearerTokenAsync(...);
+var parsedData = await client.Service.GetWithBearerTokenAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
index 2fef69c21dd9..4a30e997b631 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
index be56145f3b33..ce1a779daff3 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
index 746e89db4bba..d55c32c4307c 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
index a821e891e4df..315e861c38f5 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
index 055f52f78c95..38e60d1a36d7 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
index d5fd4e784eda..e3ebc329b797 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
@@ -87,6 +87,7 @@ internal ClientOptions Clone()
Timeout = Timeout,
Headers = new Headers(new Dictionary(Headers)),
AdditionalHeaders = AdditionalHeaders,
+ Version = Version,
};
}
}
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
index 1339ae5a665a..63268abc22ec 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
index ac92b885f7ca..5a8e83564eb6 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
+++ b/seed/csharp-sdk/bearer-token-environment-variable/no-custom-config/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/bearer-token-environment-variable/fern
+ https://github.com/bearer-token-environment-variable/fern
+ git
true
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md
index 10c97d17b96a..080bf11c1282 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.GetWithBearerTokenAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.GetWithBearerTokenAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.GetWithBearerTokenAsync(...);
+var parsedData = await client.Service.GetWithBearerTokenAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
index 2fef69c21dd9..4a30e997b631 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
index be56145f3b33..ce1a779daff3 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
index 746e89db4bba..d55c32c4307c 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
index a821e891e4df..315e861c38f5 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
index 055f52f78c95..38e60d1a36d7 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBearerTokenEnvironmentVariable.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
index c2ccbdc5ff31..aa760d4142a9 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/Public/ClientOptions.cs
@@ -17,6 +17,7 @@ internal ClientOptions(ClientOptions other)
Timeout = other.Timeout;
Headers = new Headers(new Dictionary(other.Headers));
AdditionalHeaders = other.AdditionalHeaders;
+ Version = other.Version;
ApiKey = other.ApiKey;
}
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
index 1339ae5a665a..63268abc22ec 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
index ac92b885f7ca..5a8e83564eb6 100644
--- a/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
+++ b/seed/csharp-sdk/bearer-token-environment-variable/unified-client-options/src/SeedBearerTokenEnvironmentVariable/SeedBearerTokenEnvironmentVariable.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/bearer-token-environment-variable/fern
+ https://github.com/bearer-token-environment-variable/fern
+ git
true
diff --git a/seed/csharp-sdk/bytes-download/README.md b/seed/csharp-sdk/bytes-download/README.md
index edeeae5f7132..e3fd9ebc81b4 100644
--- a/seed/csharp-sdk/bytes-download/README.md
+++ b/seed/csharp-sdk/bytes-download/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.SimpleAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.SimpleAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.SimpleAsync(...);
+var parsedData = await client.Service.SimpleAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs
index 106ee59967e5..01eca6678cbc 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs
index b9f6758307f6..33f3af6d63dc 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs
index 23f6bf634614..017ea71fa9c0 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBytesDownload.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBytesDownload.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs
index e7f71acad46e..9b523807dfd2 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs
index 7f0809999a58..48bbf03e7d44 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBytesDownload.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs
index 083b6dd63cca..0312825950b2 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj
index 1cddf5921ab4..1475204f4575 100644
--- a/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj
+++ b/seed/csharp-sdk/bytes-download/src/SeedBytesDownload/SeedBytesDownload.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/bytes-download/fern
+ https://github.com/bytes-download/fern
+ git
true
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs
index 7d957f123a97..2906c452a810 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs
index c0cd651e604c..e31c158a6f84 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs
index f3b275daf6e6..566e50d17358 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedBytesUpload.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedBytesUpload.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs
index 3e14588bb222..359ed0bcc446 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs
index 869393c741d5..43de186fc252 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedBytesUpload.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs
index 6372bc4b9dca..33ab582ada01 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj
index 01517fa69151..4e668a36ab6f 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/SeedBytesUpload.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/bytes-upload/fern
+ https://github.com/bytes-upload/fern
+ git
true
diff --git a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs
index 0d384dc567b4..badb80f3a234 100644
--- a/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs
+++ b/seed/csharp-sdk/bytes-upload/src/SeedBytesUpload/Service/ServiceClient.cs
@@ -127,9 +127,6 @@ private async Task UploadWithQueryParamsAsyncCore(
}
}
- ///
- /// await client.Service.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("[bytes]")));
- ///
public WithRawResponseTask UploadAsync(
Stream request,
RequestOptions? options = null,
@@ -139,11 +136,6 @@ public WithRawResponseTask UploadAsync(
return new WithRawResponseTask(UploadAsyncCore(request, options, cancellationToken));
}
- ///
- /// await client.Service.UploadWithQueryParamsAsync(
- /// new UploadWithQueryParamsRequest { Model = "nova-2" }
- /// );
- ///
public WithRawResponseTask UploadWithQueryParamsAsync(
UploadWithQueryParamsRequest request,
RequestOptions? options = null,
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs
index aa38cc5bc2ab..eb16fd072fff 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Ast/Types/ContainerValue.cs
@@ -58,7 +58,7 @@ public ContainerValue(ContainerValue.Optional value)
public bool IsOptional => Type == "optional";
///
- /// Returns the value as a if is 'list', otherwise throws an exception.
+ /// Returns the value as a if is 'list', otherwise throws an exception.
///
/// Thrown when is not 'list'.
public IEnumerable AsList() =>
@@ -67,7 +67,7 @@ public IEnumerable AsList() =>
: throw new global::System.Exception("ContainerValue.Type is not 'list'");
///
- /// Returns the value as a if is 'optional', otherwise throws an exception.
+ /// Returns the value as a if is 'optional', otherwise throws an exception.
///
/// Thrown when is not 'optional'.
public FieldValue? AsOptional() =>
@@ -110,7 +110,7 @@ public void Visit(
}
///
- /// Attempts to cast the value to a and returns true if successful.
+ /// Attempts to cast the value to a and returns true if successful.
///
public bool TryAsList(out IEnumerable? value)
{
@@ -124,7 +124,7 @@ public bool TryAsList(out IEnumerable? value)
}
///
- /// Attempts to cast the value to a and returns true if successful.
+ /// Attempts to cast the value to a and returns true if successful.
///
public bool TryAsOptional(out FieldValue? value)
{
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj
index ce64f98ea32a..97a7dc929db5 100644
--- a/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/circular-references-advanced/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/circular-references-advanced/fern
+ https://github.com/circular-references-advanced/fern
+ git
true
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj
index fea32093da1c..61cee493e40c 100644
--- a/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/circular-references-extends/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/circular-references-extends/fern
+ https://github.com/circular-references-extends/fern
+ git
true
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs
index aa38cc5bc2ab..eb16fd072fff 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Ast/Types/ContainerValue.cs
@@ -58,7 +58,7 @@ public ContainerValue(ContainerValue.Optional value)
public bool IsOptional => Type == "optional";
///
- /// Returns the value as a if is 'list', otherwise throws an exception.
+ /// Returns the value as a if is 'list', otherwise throws an exception.
///
/// Thrown when is not 'list'.
public IEnumerable AsList() =>
@@ -67,7 +67,7 @@ public IEnumerable AsList() =>
: throw new global::System.Exception("ContainerValue.Type is not 'list'");
///
- /// Returns the value as a if is 'optional', otherwise throws an exception.
+ /// Returns the value as a if is 'optional', otherwise throws an exception.
///
/// Thrown when is not 'optional'.
public FieldValue? AsOptional() =>
@@ -110,7 +110,7 @@ public void Visit(
}
///
- /// Attempts to cast the value to a and returns true if successful.
+ /// Attempts to cast the value to a and returns true if successful.
///
public bool TryAsList(out IEnumerable? value)
{
@@ -124,7 +124,7 @@ public bool TryAsList(out IEnumerable? value)
}
///
- /// Attempts to cast the value to a and returns true if successful.
+ /// Attempts to cast the value to a and returns true if successful.
///
public bool TryAsOptional(out FieldValue? value)
{
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj
index c1c31c4be40b..5aca45084a95 100644
--- a/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/circular-references/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/circular-references/fern
+ https://github.com/circular-references/fern
+ git
true
diff --git a/seed/csharp-sdk/client-side-params/README.md b/seed/csharp-sdk/client-side-params/README.md
index 8293b36b0154..a638dbfc02ca 100644
--- a/seed/csharp-sdk/client-side-params/README.md
+++ b/seed/csharp-sdk/client-side-params/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -115,7 +118,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.SearchResourcesAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -128,7 +131,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.SearchResourcesAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -158,7 +161,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.SearchResourcesAsync(...);
+var parsedData = await client.Service.SearchResourcesAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs
index f8e6183bb0ca..b191d0dcc69e 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs
index e30ee9595307..be4421147b7b 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs
index 2ba7f7d6c356..10498d8b396d 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedClientSideParams.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedClientSideParams.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs
index c52ce95e4cba..fa5659ae74ef 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs
index 0a0869754ee7..15f2520398f3 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedClientSideParams.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs
index 7375bb10e696..a34df3aefbd4 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj
index dcd2a92ae1ee..475a3f5b1df3 100644
--- a/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj
+++ b/seed/csharp-sdk/client-side-params/src/SeedClientSideParams/SeedClientSideParams.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/client-side-params/fern
+ https://github.com/client-side-params/fern
+ git
true
diff --git a/seed/csharp-sdk/content-type/README.md b/seed/csharp-sdk/content-type/README.md
index eac0ac505a34..46b02e755cb4 100644
--- a/seed/csharp-sdk/content-type/README.md
+++ b/seed/csharp-sdk/content-type/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -103,7 +106,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.PatchAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -116,7 +119,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.PatchAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -146,7 +149,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.PatchAsync(...);
+var parsedData = await client.Service.PatchAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs
index c412777769c7..eb5dae373a3d 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs
index 0c4cabccbdcf..47753c043726 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs
index 26873c5e7c5b..1414c3a72f9f 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedContentTypes.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedContentTypes.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs
index aa194ac4a2b3..ab8c87efdb90 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs
index 8f70cd30ae2a..ced169b4056b 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedContentTypes.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs
index 88200476d04d..84572159efe4 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj b/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj
index 56d6d2d3cc78..e9df062b4764 100644
--- a/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj
+++ b/seed/csharp-sdk/content-type/src/SeedContentTypes/SeedContentTypes.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/content-type/fern
+ https://github.com/content-type/fern
+ git
true
diff --git a/seed/csharp-sdk/cross-package-type-names/README.md b/seed/csharp-sdk/cross-package-type-names/README.md
index 02ffcaf9d89d..02422f865886 100644
--- a/seed/csharp-sdk/cross-package-type-names/README.md
+++ b/seed/csharp-sdk/cross-package-type-names/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -108,7 +111,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Foo.FindAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -121,7 +124,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Foo.FindAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -151,7 +154,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Foo.FindAsync(...);
+var parsedData = await client.Foo.FindAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs
index bad8767e61cb..846147ad9b56 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs
index 5d451bf9cab9..2112f866b1c2 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs
index 382797c8b543..9754e915bcfe 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedCrossPackageTypeNames.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedCrossPackageTypeNames.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs
index 51387d737f25..a43e19f5db67 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs
index 2b7ab3d8e1d3..1b37020485df 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedCrossPackageTypeNames.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs
index 60fbb47f80f2..780a9327e71b 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj
index 863bca101206..812a9d474b86 100644
--- a/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj
+++ b/seed/csharp-sdk/cross-package-type-names/src/SeedCrossPackageTypeNames/SeedCrossPackageTypeNames.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/cross-package-type-names/fern
+ https://github.com/cross-package-type-names/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-global-header-env/README.md b/seed/csharp-sdk/csharp-global-header-env/README.md
index 583dc65535e2..dfa30c4822df 100644
--- a/seed/csharp-sdk/csharp-global-header-env/README.md
+++ b/seed/csharp-sdk/csharp-global-header-env/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -42,7 +45,7 @@ Instantiate and use the client with the following:
```csharp
using SeedCsharpGlobalHeaderEnv;
-var client = new SeedCsharpGlobalHeaderEnvClient("USERNAME", "PASSWORD", "TOKEN", "VERSION");
+var client = new SeedCsharpGlobalHeaderEnvClient("USERNAME", "PASSWORD", "TOKEN", "2024-01-01");
await client.Service.GetWithApiVersionAsync();
```
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.GetWithApiVersionAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.GetWithApiVersionAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.GetWithApiVersionAsync(...);
+var parsedData = await client.Service.GetWithApiVersionAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/csharp-global-header-env/snippet.json b/seed/csharp-sdk/csharp-global-header-env/snippet.json
index a367f6a66aad..68abe9f12ba3 100644
--- a/seed/csharp-sdk/csharp-global-header-env/snippet.json
+++ b/seed/csharp-sdk/csharp-global-header-env/snippet.json
@@ -10,7 +10,7 @@
},
"snippet": {
"type": "csharp",
- "client": "using SeedCsharpGlobalHeaderEnv;\n\nvar client = new SeedCsharpGlobalHeaderEnvClient(\"USERNAME\", \"PASSWORD\", \"TOKEN\", \"VERSION\");\nawait client.Service.GetWithApiVersionAsync();\n"
+ "client": "using SeedCsharpGlobalHeaderEnv;\n\nvar client = new SeedCsharpGlobalHeaderEnvClient(\"USERNAME\", \"PASSWORD\", \"TOKEN\", \"2024-01-01\");\nawait client.Service.GetWithApiVersionAsync();\n"
}
}
]
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs
index 2ed244fc69ff..b33af5f1749a 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Unit/MockServer/BaseMockServerTest.cs
@@ -27,7 +27,7 @@ public void GlobalSetup()
"USERNAME",
"PASSWORD",
"TOKEN",
- "VERSION",
+ "2024-01-01",
clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 }
);
}
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs
index c641b2216ef9..fda74aec6fa0 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs
index 7394bec11d3d..86d193dd2d52 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs
index e9c387ed1753..d8fe59354026 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedCsharpGlobalHeaderEnv.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedCsharpGlobalHeaderEnv.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs
index 715ef60a27ee..c52cb8301009 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs
index 6acff0a52c28..a8c9ee4cb57d 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedCsharpGlobalHeaderEnv.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs
index 228e2a2e4835..ea1112b7dfee 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj
index 1133eb81104b..f9828b9bd966 100644
--- a/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj
+++ b/seed/csharp-sdk/csharp-global-header-env/src/SeedCsharpGlobalHeaderEnv/SeedCsharpGlobalHeaderEnv.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/csharp-global-header-env/fern
+ https://github.com/csharp-global-header-env/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json b/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json
index b5663320f931..3274387319e1 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/.fern/metadata.json
@@ -1,7 +1,7 @@
{
"cliVersion": "DUMMY",
"generatorName": "fernapi/fern-csharp-sdk",
- "generatorVersion": "latest",
+ "generatorVersion": "local",
"generatorConfig": {},
"originGitCommit": "DUMMY",
"invokedBy": "manual",
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/README.md b/seed/csharp-sdk/csharp-global-header-literal-env/README.md
index 40dc75ff7eb0..530379f8303e 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/README.md
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/README.md
@@ -24,6 +24,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -42,7 +45,7 @@ Instantiate and use the client with the following:
```csharp
using SeedCsharpGlobalHeaderLiteralEnv;
-var client = new SeedCsharpGlobalHeaderLiteralEnvClient("TOKEN", "VERSION");
+var client = new SeedCsharpGlobalHeaderLiteralEnvClient("TOKEN", "2026-07-15");
await client.Service.GetWithLiteralVersionHeaderAsync();
```
@@ -101,7 +104,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.Service.GetWithLiteralVersionHeaderAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -114,7 +117,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.Service.GetWithLiteralVersionHeaderAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
@@ -144,7 +147,7 @@ if (headers.TryGetValue("X-Request-Id", out var requestId))
}
// For the default behavior, simply await without .WithRawResponse()
-var data = await client.Service.GetWithLiteralVersionHeaderAsync(...);
+var parsedData = await client.Service.GetWithLiteralVersionHeaderAsync(...);
// .WithRawResponse() also works on streaming endpoints (returns IAsyncEnumerable + RawResponse)
// and on endpoints with no response body (returns RawResponse only).
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json b/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json
index f67064e52131..227455777e18 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/snippet.json
@@ -10,7 +10,7 @@
},
"snippet": {
"type": "csharp",
- "client": "using SeedCsharpGlobalHeaderLiteralEnv;\n\nvar client = new SeedCsharpGlobalHeaderLiteralEnvClient(\"TOKEN\", \"VERSION\");\nawait client.Service.GetWithLiteralVersionHeaderAsync();\n"
+ "client": "using SeedCsharpGlobalHeaderLiteralEnv;\n\nvar client = new SeedCsharpGlobalHeaderLiteralEnvClient(\"TOKEN\", \"2026-07-15\");\nawait client.Service.GetWithLiteralVersionHeaderAsync();\n"
}
}
]
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs
index 7bc4f19c7278..bbdc8684c494 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Unit/MockServer/BaseMockServerTest.cs
@@ -25,7 +25,7 @@ public void GlobalSetup()
// Initialize the Client
Client = new SeedCsharpGlobalHeaderLiteralEnvClient(
"TOKEN",
- "VERSION",
+ "2026-07-15",
clientOptions: new ClientOptions { BaseUrl = Server.Urls[0], MaxRetries = 0 }
);
}
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs
index aae731a5dbda..6c5135068429 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs
index 7cd2007ffd45..fd400930ea93 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs
index 59ff381d876b..1f050b791961 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs
index 5e787718c8ae..e81285ed85bb 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs
index 62992a73fd7f..45bad46de719 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedCsharpGlobalHeaderLiteralEnv.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs
index 93670833fa80..b05143ddf178 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/Public/ClientOptions.cs
@@ -87,6 +87,7 @@ internal ClientOptions Clone()
Timeout = Timeout,
Headers = new Headers(new Dictionary(Headers)),
AdditionalHeaders = AdditionalHeaders,
+ Version = Version,
};
}
}
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs
index fb8cd80a4628..1db3740134cf 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj
index 9cdd222e57e3..9443d281dc0a 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnv.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/csharp-global-header-literal-env/fern
+ https://github.com/csharp-global-header-literal-env/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs
index eed293756061..a735a138b540 100644
--- a/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs
+++ b/seed/csharp-sdk/csharp-global-header-literal-env/src/SeedCsharpGlobalHeaderLiteralEnv/SeedCsharpGlobalHeaderLiteralEnvClient.cs
@@ -17,6 +17,7 @@ public SeedCsharpGlobalHeaderLiteralEnvClient(
"SQUARE_TOKEN",
"Please pass in token or set the environment variable SQUARE_TOKEN."
);
+ Version ??= clientOptions?.Version;
Version ??= Environment.GetEnvironmentVariable("VERSION") ?? "2026-07-15";
clientOptions ??= new ClientOptions();
var platformHeaders = new Headers(
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md
index 27e3fbd8ae14..bfd62ad7f569 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/README.md
@@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj
index f108be921720..aec58e39115a 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/include-exception-handler/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/csharp-grpc-proto-exhaustive/fern
+ https://github.com/csharp-grpc-proto-exhaustive/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md
index 27e3fbd8ae14..bfd62ad7f569 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/README.md
@@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj
index f108be921720..aec58e39115a 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/no-custom-config/src/SeedApi/SeedApi.csproj
@@ -8,7 +8,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/csharp-grpc-proto-exhaustive/fern
+ https://github.com/csharp-grpc-proto-exhaustive/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md
index 27e3fbd8ae14..bfd62ad7f569 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/README.md
@@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable] Optional<string?> → can be undefined, null, or a value
+/// - [Optional] Optional<string> → can be undefined or a value (null is invalid)
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class OptionalAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs
index 2a7255f9993a..04ecc2efa5e3 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/Core/QueryStringBuilder.cs
@@ -119,10 +119,10 @@ public static string EncodePathSegment(string value)
#endif
}
+#if NET6_0_OR_GREATER
///
/// Builds a query string from the provided parameters.
///
-#if NET6_0_OR_GREATER
public static string Build(ReadOnlySpan> parameters)
{
if (parameters.IsEmpty)
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj
index 78043dc7d01e..2fd4816c690d 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/package-id/src/SeedApi/SeedApi.csproj
@@ -9,7 +9,11 @@
$(Version)
$(Version)
README.md
+ true
+ $(NoWarn);CS1591
https://github.com/csharp-grpc-proto-exhaustive/fern
+ https://github.com/csharp-grpc-proto-exhaustive/fern
+ git
true
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md
index 27e3fbd8ae14..bfd62ad7f569 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/README.md
@@ -23,6 +23,9 @@ The Seed C# library provides convenient access to the Seed APIs from C#.
## Requirements
This SDK requires:
+- .NET 8 and above
+- .NET Framework 4.6.2 and above
+- .NET Standard 2.0 and above
## Installation
@@ -113,7 +116,7 @@ Use the `MaxRetries` request option to configure this behavior.
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- MaxRetries: 0 // Override MaxRetries at the request level
+ MaxRetries = 0 // Override MaxRetries at the request level
}
);
```
@@ -126,7 +129,7 @@ The SDK defaults to a 30 second timeout. Use the `Timeout` option to configure t
var response = await client.DataService.CheckAsync(
...,
new RequestOptions {
- Timeout: TimeSpan.FromSeconds(3) // Override timeout to 3s
+ Timeout = TimeSpan.FromSeconds(3) // Override timeout to 3s
}
);
```
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs
index 98bfcac477b8..f816065d36e0 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi.Test/Utils/OptionalComparer.cs
@@ -65,7 +65,7 @@ public static EqualConstraint UsingOptionalComparer(this EqualConstraint constra
///
/// EqualityAdapter for comparing IOneOf instances within NUnitEqualityComparer.
- /// This enables recursive comparison of nested OneOf values within Optional types.
+ /// This enables recursive comparison of nested OneOf values within Optional<T> types.
///
private class OneOfEqualityAdapter : EqualityAdapter
{
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs
index 7338b20e748c..ed17f99952fb 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Extensions.cs
@@ -20,6 +20,7 @@ public static string Stringify(this Enum value)
///
/// Asserts that a condition is true, throwing an exception with the specified message if it is false.
///
+ /// The object the extension method is invoked on; unused.
/// The condition to assert.
/// The exception message if the assertion fails.
/// Thrown when the condition is false.
@@ -35,6 +36,7 @@ internal static void Assert(this object value, bool condition, string message)
/// Asserts that a value is not null, throwing an exception with the specified message if it is null.
///
/// The type of the value to assert.
+ /// The object the extension method is invoked on; unused.
/// The value to assert is not null.
/// The exception message if the assertion fails.
/// The non-null value.
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs
index a1d30328bf9a..8e57fe6e0d1b 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/NullableAttribute.cs
@@ -2,7 +2,7 @@ namespace SeedApi.Core;
///
/// Marks a property as nullable in the OpenAPI specification.
-/// When applied to Optional properties, this indicates that null values should be
+/// When applied to Optional<T> properties, this indicates that null values should be
/// written to JSON when the optional is defined with null.
///
///
@@ -10,9 +10,9 @@ namespace SeedApi.Core;
/// - Without [Nullable]: null values are invalid (omit from JSON at runtime)
/// - With [Nullable]: null values are written to JSON
///
-/// For Optional properties (also marked with [Optional]):
-/// - Without [Nullable]: Optional.Of(null) → omit from JSON (runtime edge case)
-/// - With [Nullable]: Optional.Of(null) → write null to JSON
+/// For Optional<T> properties (also marked with [Optional]):
+/// - Without [Nullable]: Optional<T>.Of(null) → omit from JSON (runtime edge case)
+/// - With [Nullable]: Optional<T?>.Of(null) → write null to JSON
///
[global::System.AttributeUsage(global::System.AttributeTargets.Property, AllowMultiple = false)]
public class NullableAttribute : global::System.Attribute { }
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs
index d174943cb2cf..2efc4945ec72 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/Optional.cs
@@ -263,7 +263,7 @@ public override int GetHashCode()
}
///
-/// Extension methods for Optional to simplify common operations.
+/// Extension methods for Optional<T> to simplify common operations.
///
public static class OptionalExtensions
{
@@ -341,7 +341,7 @@ Func mapper
/// Adds a nullable value to a dictionary only if it is not null.
/// This is useful for regular nullable properties where null means "omit from request".
///
- /// The type of the value (must be a reference type or Nullable).
+ /// The type of the value (must be a reference type or Nullable<T>).
/// The nullable value to add.
/// The dictionary to add to.
/// The key to use in the dictionary.
@@ -395,7 +395,7 @@ string key
}
///
-/// JSON converter factory for Optional that handles undefined vs null correctly.
+/// JSON converter factory for Optional<T> that handles undefined vs null correctly.
/// Uses a TypeInfoResolver to conditionally include/exclude properties based on Optional.IsDefined.
///
public class OptionalJsonConverterFactory : JsonConverterFactory
@@ -420,7 +420,7 @@ JsonSerializerOptions options
}
///
-/// JSON converter for Optional that unwraps the value during serialization.
+/// JSON converter for Optional<T> that unwraps the value during serialization.
/// The actual property skipping is handled by the OptionalTypeInfoResolver.
///
public class OptionalJsonConverter : JsonConverter>
diff --git a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs
index 4c4c4073a0ae..543e999e42d6 100644
--- a/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs
+++ b/seed/csharp-sdk/csharp-grpc-proto-exhaustive/read-only-memory/src/SeedApi/Core/OptionalAttribute.cs
@@ -2,16 +2,16 @@ namespace SeedApi.Core;
///
/// Marks a property as optional in the OpenAPI specification.
-/// Optional properties use the Optional type and can be undefined (not present in JSON).
+/// Optional properties use the Optional<T> type and can be undefined (not present in JSON).
///
///
-/// Properties marked with [Optional] should use the Optional type:
-/// - Undefined: Optional.Undefined → omitted from JSON
-/// - Defined: Optional.Of(value) → written to JSON
+/// Properties marked with [Optional] should use the Optional<T> type:
+/// - Undefined: Optional<T>.Undefined → omitted from JSON
+/// - Defined: Optional<T>.Of(value) → written to JSON
///
/// Combine with [Nullable] to allow null values:
-/// - [Optional, Nullable] Optional → can be undefined, null, or a value
-/// - [Optional] Optional → can be undefined or a value (null is invalid)
+/// - [Optional, Nullable]