Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b1e0cc4
feat(csharp): add support for inferred authentication scheme
devin-ai-integration[bot] Dec 9, 2025
f067338
fix(csharp): fix TypeScript compile errors and update seed output for…
devin-ai-integration[bot] Dec 9, 2025
3550a00
fix(csharp): fix property naming in inferred auth request initializer
devin-ai-integration[bot] Dec 9, 2025
f2756fa
feat(csharp): implement inferred authentication support across SDK cl…
Swimburger Dec 10, 2025
c05e31f
Merge branch 'main' into devin/1765244724-csharp-inferred-auth
fern-support Dec 10, 2025
2f617cc
seed
Swimburger Dec 11, 2025
80b8b71
seed
Swimburger Dec 11, 2025
90a5d5b
Refactor authentication client initialization to include scope parameter
Swimburger Dec 11, 2025
e4bc995
refactor: streamline token endpoint identification and credential ext…
Swimburger Dec 11, 2025
1432ed9
inferred updates
Swimburger Dec 11, 2025
121ea51
Merge branch 'main' of https://github.com/fern-api/fern into devin/17…
Swimburger Dec 11, 2025
76967d2
Merge branch 'main' of https://github.com/fern-api/fern into devin/17…
Swimburger Dec 11, 2025
06fa7dc
fix(csharp): update authorization header handling to use async Func<V…
Swimburger Dec 11, 2025
3dd5e81
Update IR in csharp generator
Swimburger Dec 11, 2025
022e61b
Merge branch 'main' of https://github.com/fern-api/fern into devin/17…
Swimburger Dec 11, 2025
40a4409
feat: update C# SDK and model to version 62, including auth examples
Swimburger Dec 12, 2025
d3bbbe1
feat(csharp): implement thread-safe token handling and update IR vers…
Swimburger Dec 12, 2025
8474612
feat(csharp): enhance token provider with error handling and caching …
Swimburger Dec 12, 2025
a1ba2af
feat: Implement RawClient for handling raw HTTP requests with retries…
Swimburger Dec 12, 2025
5c628b9
Refactor code for improved readability and consistency
Swimburger Dec 12, 2025
87355d5
feat(csharp): refactor inferred auth handling to use collectInferredA…
Swimburger Dec 12, 2025
8d8ce9b
Add JSON schema snapshots for authentication requests and responses
Swimburger Dec 12, 2025
e88b7e6
feat: add inferred auth endpoint paths for testing
Swimburger Dec 12, 2025
c30323c
fix: update changelog entry type for inferred auth dynamic IR generation
Swimburger Dec 12, 2025
587ed18
fix: update snapshot names for broken links and init tests for clarity
Swimburger Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion generators/browser-compatible-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"dependencies": {
"@fern-api/core-utils": "workspace:*",
"@fern-api/dynamic-ir-sdk": "^61.7.0",
"@fern-api/dynamic-ir-sdk": "^62.3.0",
"@fern-api/fern-definition-schema": "workspace:*",
"@fern-api/logger": "workspace:*",
"@fern-api/path-utils": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@fern-api/csharp-codegen": "workspace:*",
"@fern-api/fs-utils": "workspace:*",
"@fern-api/logging-execa": "workspace:*",
"@fern-fern/ir-sdk": "^61.7.0",
"@fern-fern/ir-sdk": "^62.3.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "18.15.3",
"depcheck": "^1.4.7",
Expand Down
4 changes: 2 additions & 2 deletions generators/csharp/codegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"dependencies": {
"@fern-api/browser-compatible-base-generator": "workspace:*",
"@fern-api/core-utils": "workspace:*",
"@fern-api/dynamic-ir-sdk": "^61.7.0",
"@fern-fern/ir-sdk": "^61.7.0",
"@fern-api/dynamic-ir-sdk": "^62.3.0",
"@fern-fern/ir-sdk": "^62.3.0",
"zod": "^3.22.3"
},
"devDependencies": {
Expand Down
10 changes: 9 additions & 1 deletion generators/csharp/codegen/src/context/generation-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ export class Generation {
}),
methods: lazy({
mockOauth: () => "MockOAuthEndpoint",
getAccessTokenAsync: () => "GetAccessTokenAsync"
mockInferredAuth: () => "MockInferredAuthEndpoint",
getAccessTokenAsync: () => "GetAccessTokenAsync",
getAuthHeadersAsync: () => "GetAuthHeadersAsync"
}),
variables: lazy({
client: () => "client",
Expand Down Expand Up @@ -686,6 +688,12 @@ export class Generation {
origin: this.model.staticExplicit("OAuthTokenProvider"),
namespace: this.namespaces.core
}),
/** Inferred auth token provider for authentication */
InferredAuthTokenProvider: () =>
this.csharp.classReference({
origin: this.model.staticExplicit("InferredAuthTokenProvider"),
namespace: this.namespaces.core
}),
/** Converter for Protocol Buffer types */
ProtoConverter: () =>
this.csharp.classReference({
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/dynamic-snippets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@fern-api/configs": "workspace:*",
"@fern-api/core-utils": "workspace:*",
"@fern-api/csharp-codegen": "workspace:*",
"@fern-api/dynamic-ir-sdk": "61.4.0",
"@fern-api/dynamic-ir-sdk": "^62.3.0",
"@fern-api/path-utils": "workspace:*",
"@types/lodash-es": "^4.17.12",
"@types/node": "18.15.3",
Expand Down
40 changes: 38 additions & 2 deletions generators/csharp/dynamic-snippets/src/EndpointSnippetGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ export class EndpointSnippetGenerator extends WithGeneration {
snippet: FernIr.dynamic.EndpointSnippetRequest;
}): NamedArgument[] {
const authArgs: NamedArgument[] = [];

// Check if the API uses inferred auth by looking for a token endpoint
if (endpoint.auth != null) {
if (snippet.auth != null) {
authArgs.push(...this.getConstructorAuthArgs({ auth: endpoint.auth, values: snippet.auth }));
Expand Down Expand Up @@ -324,8 +326,7 @@ export class EndpointSnippetGenerator extends WithGeneration {
case "oauth":
return values.type === "oauth" ? this.getConstructorOAuthArgs({ auth, values }) : [];
case "inferred":
this.addWarning("The C# SDK Generator does not support Inferred auth scheme yet");
return [];
return values.type === "inferred" ? this.getConstructorInferredAuthArgs({ auth, values }) : [];
default:
assertNever(auth);
}
Expand Down Expand Up @@ -411,6 +412,41 @@ export class EndpointSnippetGenerator extends WithGeneration {
];
}

private getConstructorInferredAuthArgs({
auth,
values
}: {
auth: FernIr.dynamic.InferredAuth;
values: FernIr.dynamic.InferredAuthValues;
}): NamedArgument[] {
const args: NamedArgument[] = [];

// Use parameters from the IR
if (auth.parameters != null) {
for (const param of auth.parameters) {
const wireValue = param.name.wireValue;
const value = values.values?.[wireValue];

args.push({
name: this.context.getParameterName(param.name.name),
assignment: this.context.dynamicLiteralMapper.convert({
typeReference: param.typeReference,
value: value,
fallbackToDefault: wireValue
})
});
}
} else {
this.context.errors.add({
severity: Severity.Critical,
message:
"Inferred auth parameters are not defined in the IR. Please ensure you're using IR version 62.3.0 or later."
});
}

return args;
}

private getConstructorHeaderArgs({
headers,
values
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@fern-api/csharp-codegen": "workspace:*",
"@fern-api/csharp-formatter": "workspace:*",
"@fern-api/fs-utils": "workspace:*",
"@fern-fern/ir-sdk": "^61.7.0",
"@fern-fern/ir-sdk": "^62.3.0",
"@types/node": "18.15.3",
"depcheck": "^1.4.7",
"typescript": "5.9.3",
Expand Down
7 changes: 7 additions & 0 deletions generators/csharp/model/versions.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
- version: 0.0.6
changelogEntry:
- type: internal
summary: Upgrade to IR version 61.
createdAt: "2025-12-11"
irVersion: 62

- version: 0.0.5
changelogEntry:
- type: chore
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"@fern-api/logger": "workspace:*",
"@fern-fern/generator-cli-sdk": "^0.1.5",
"@fern-fern/generator-exec-sdk": "^0.0.1167",
"@fern-fern/ir-sdk": "^61.7.0",
"@fern-fern/ir-sdk": "^62.3.0",
"@types/node": "18.15.3",
"@types/url-join": "4.0.1",
"depcheck": "^1.4.7",
Expand Down
15 changes: 14 additions & 1 deletion generators/csharp/sdk/src/SdkGeneratorCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { BaseExceptionGenerator } from "./error/BaseExceptionGenerator";
import { CustomExceptionInterceptorGenerator } from "./error/CustomExceptionInterceptorGenerator";
import { ErrorGenerator } from "./error/ErrorGenerator";
import { generateSdkTests } from "./generateSdkTests";
import { InferredAuthTokenProviderGenerator } from "./inferred-auth/InferredAuthTokenProviderGenerator";
import { OauthTokenProviderGenerator } from "./oauth/OauthTokenProviderGenerator";
import { BaseOptionsGenerator } from "./options/BaseOptionsGenerator";
import { ClientOptionsGenerator } from "./options/ClientOptionsGenerator";
Expand Down Expand Up @@ -242,6 +243,15 @@ export class SdkGeneratorCLI extends AbstractCsharpGeneratorCli {
context.project.addSourceFiles(oauthTokenProvider.generate());
}

const inferred = context.getInferredAuth();
if (inferred != null) {
const inferredAuthTokenProvider = new InferredAuthTokenProviderGenerator({
context,
scheme: inferred
});
context.project.addSourceFiles(inferredAuthTokenProvider.generate());
}

const testGenerator = new TestFileGenerator(context);
const test = testGenerator.generate();
context.project.addTestFiles(test);
Expand Down Expand Up @@ -282,7 +292,10 @@ export class SdkGeneratorCLI extends AbstractCsharpGeneratorCli {
context.logger.debug("No snippets were produced; skipping README.md generation.");
return;
}
const content = await context.generatorAgent.generateReadme({ context, endpointSnippets });
const content = await context.generatorAgent.generateReadme({
context,
endpointSnippets
});
const otherPath = context.settings.outputPath.other;
context.project.addRawFiles(
new File(context.generatorAgent.README_FILENAME, RelativeFilePath.of(otherPath), content)
Expand Down
10 changes: 10 additions & 0 deletions generators/csharp/sdk/src/SdkGeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
FernFilepath,
HttpEndpoint,
HttpService,
InferredAuthScheme,
IntermediateRepresentation,
Name,
NameAndWireValue,
Expand Down Expand Up @@ -323,6 +324,15 @@ export class SdkGeneratorContext extends GeneratorContext {
return undefined;
}

public getInferredAuth(): InferredAuthScheme | undefined {
for (const scheme of this.ir.auth.schemes) {
if (scheme.type === "inferred") {
return scheme;
}
}
return undefined;
}

public resolveEndpoint(service: HttpService, endpointId: EndpointId): HttpEndpoint {
const httpEndpoint = service.endpoints.find((endpoint) => endpoint.id === endpointId);
if (httpEndpoint == null) {
Expand Down
19 changes: 15 additions & 4 deletions generators/csharp/sdk/src/endpoint/AbstractEndpointGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { EndpointSignatureInfo } from "./EndpointSignatureInfo";
import { getEndpointRequest } from "./utils/getEndpointRequest";
import { getEndpointReturnType } from "./utils/getEndpointReturnType";

type PagingEndpoint = HttpEndpoint & { pagination: NonNullable<HttpEndpoint["pagination"]> };
type PagingEndpoint = HttpEndpoint & {
pagination: NonNullable<HttpEndpoint["pagination"]>;
};

export abstract class AbstractEndpointGenerator extends WithGeneration {
private exampleGenerator: ExampleGenerator;
Expand Down Expand Up @@ -69,10 +71,17 @@ export abstract class AbstractEndpointGenerator extends WithGeneration {
endpoint: HttpEndpoint;
endpointType: "unpaged" | "paged";
}): EndpointSignatureInfo {
const request = getEndpointRequest({ context: this.context, endpoint, serviceId });
const request = getEndpointRequest({
context: this.context,
endpoint,
serviceId
});
const requestParameter =
request != null
? this.csharp.parameter({ type: request.getParameterType(), name: request.getParameterName() })
? this.csharp.parameter({
type: request.getParameterType(),
name: request.getParameterName()
})
: undefined;
const { pathParameters, pathParameterReferences } = this.getAllPathParameters({
endpoint,
Expand Down Expand Up @@ -154,7 +163,9 @@ export abstract class AbstractEndpointGenerator extends WithGeneration {
this.csharp.parameter({
docs: pathParam.docs,
name: parameterName,
type: this.context.csharpTypeMapper.convert({ reference: pathParam.valueType })
type: this.context.csharpTypeMapper.convert({
reference: pathParam.valueType
})
})
);
}
Expand Down
10 changes: 8 additions & 2 deletions generators/csharp/sdk/src/endpoint/grpc/GrpcEndpointGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export class GrpcEndpointGenerator extends AbstractEndpointGenerator {
cls: ast.Class,
{ serviceId, endpoint, rawGrpcClientReference, grpcClientInfo }: GrpcEndpointGenerator.Args
) {
const endpointSignatureInfo = this.getEndpointSignatureInfo({ serviceId, endpoint });
const endpointSignatureInfo = this.getEndpointSignatureInfo({
serviceId,
endpoint
});
const parameters = [...endpointSignatureInfo.baseParameters];
parameters.push(
this.csharp.parameter({
Expand Down Expand Up @@ -57,7 +60,10 @@ export class GrpcEndpointGenerator extends AbstractEndpointGenerator {
summary: endpoint.docs,
return_: endpointSignatureInfo.returnType,
body: this.settings.includeExceptionHandler
? this.wrapWithExceptionHandler({ body, returnType: endpointSignatureInfo.returnType })
? this.wrapWithExceptionHandler({
body,
returnType: endpointSignatureInfo.returnType
})
: body,
codeExample: snippet?.endpointCall
});
Expand Down
Loading
Loading