Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const TypescriptCustomConfigSchema = z.strictObject({
includeCredentialsOnCrossOriginRequests: z.optional(z.boolean()),
bundle: z.optional(z.boolean()),
allowCustomFetcher: z.optional(z.boolean()),
shouldGenerateWebsocketClients: z.optional(z.boolean()),
generateWebSocketClients: z.optional(z.boolean()),
defaultTimeoutInSeconds: z.optional(z.union([z.literal("infinity"), z.number()])),
skipResponseValidation: z.optional(z.boolean()),
extraDependencies: z.optional(z.record(z.string())),
Expand Down Expand Up @@ -99,6 +99,8 @@ export const TypescriptCustomConfigSchema = z.strictObject({
// deprecated
timeoutInSeconds: z.optional(z.union([z.literal("infinity"), z.number()])),
includeApiReference: z.optional(z.boolean()),
// @deprecated Use generateWebSocketClients instead
shouldGenerateWebsocketClients: z.optional(z.boolean()),

// internal - license name extracted from custom license file
_fernLicenseName: z.optional(z.string())
Expand Down
5 changes: 3 additions & 2 deletions generators/typescript/sdk/cli/src/SdkGeneratorCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export class SdkGeneratorCli extends AbstractGeneratorCli<SdkCustomConfig> {
includeCredentialsOnCrossOriginRequests: parsed?.includeCredentialsOnCrossOriginRequests ?? false,
shouldBundle: parsed?.bundle ?? false,
allowCustomFetcher: parsed?.allowCustomFetcher ?? false,
shouldGenerateWebsocketClients: parsed?.shouldGenerateWebsocketClients ?? false,
generateWebSocketClients:
parsed?.generateWebSocketClients ?? parsed?.shouldGenerateWebsocketClients ?? false,
includeUtilsOnUnionMembers: !noSerdeLayer && (parsed?.includeUtilsOnUnionMembers ?? false),
includeOtherInUnionTypes: parsed?.includeOtherInUnionTypes ?? false,
enableForwardCompatibleEnums: parsed?.enableForwardCompatibleEnums ?? false,
Expand Down Expand Up @@ -203,7 +204,7 @@ export class SdkGeneratorCli extends AbstractGeneratorCli<SdkCustomConfig> {
outputEsm: customConfig.outputEsm,
includeCredentialsOnCrossOriginRequests: customConfig.includeCredentialsOnCrossOriginRequests,
allowCustomFetcher: customConfig.allowCustomFetcher,
shouldGenerateWebsocketClients: customConfig.shouldGenerateWebsocketClients,
generateWebSocketClients: customConfig.generateWebSocketClients,
includeUtilsOnUnionMembers: customConfig.includeUtilsOnUnionMembers,
includeOtherInUnionTypes: customConfig.includeOtherInUnionTypes,
enableForwardCompatibleEnums: customConfig.enableForwardCompatibleEnums,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface SdkCustomConfig {
includeCredentialsOnCrossOriginRequests: boolean;
shouldBundle: boolean;
allowCustomFetcher: boolean;
shouldGenerateWebsocketClients: boolean;
generateWebSocketClients: boolean;
includeUtilsOnUnionMembers: boolean;
includeOtherInUnionTypes: boolean;
enableForwardCompatibleEnums: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export declare namespace GeneratedSdkClientClassImpl {
neverThrowErrors: boolean;
includeCredentialsOnCrossOriginRequests: boolean;
allowCustomFetcher: boolean;
shouldGenerateWebsocketClients: boolean;
generateWebSocketClients: boolean;
requireDefaultEnvironment: boolean;
defaultTimeoutInSeconds: number | "infinity" | undefined;
includeContentHeadersOnFileDownloadResponse: boolean;
Expand Down Expand Up @@ -107,7 +107,7 @@ export class GeneratedSdkClientClassImpl implements GeneratedSdkClientClass {
private readonly generatedWebsocketImplementation: GeneratedWebsocketImplementation | undefined;
private readonly generatedWrappedServices: GeneratedWrappedService[];
private readonly allowCustomFetcher: boolean;
private readonly shouldGenerateWebsocketClients: boolean;
private readonly generateWebSocketClients: boolean;
private readonly packageResolver: PackageResolver;
private readonly requireDefaultEnvironment: boolean;
private readonly packageId: PackageId;
Expand All @@ -134,7 +134,7 @@ export class GeneratedSdkClientClassImpl implements GeneratedSdkClientClass {
neverThrowErrors,
includeCredentialsOnCrossOriginRequests,
allowCustomFetcher,
shouldGenerateWebsocketClients,
generateWebSocketClients,
requireDefaultEnvironment,
defaultTimeoutInSeconds,
includeContentHeadersOnFileDownloadResponse,
Expand All @@ -156,7 +156,7 @@ export class GeneratedSdkClientClassImpl implements GeneratedSdkClientClass {
this.serviceClassName = serviceClassName;
this.packageId = packageId;
this.allowCustomFetcher = allowCustomFetcher;
this.shouldGenerateWebsocketClients = shouldGenerateWebsocketClients;
this.generateWebSocketClients = generateWebSocketClients;
this.packageResolver = packageResolver;
this.requireDefaultEnvironment = requireDefaultEnvironment;
this.retainOriginalCasing = retainOriginalCasing;
Expand Down Expand Up @@ -353,7 +353,7 @@ export class GeneratedSdkClientClassImpl implements GeneratedSdkClientClass {
});
}

if (websocketChannel != null && websocketChannelId != null && this.shouldGenerateWebsocketClients) {
if (websocketChannel != null && websocketChannelId != null && this.generateWebSocketClients) {
this.generatedWebsocketImplementation = new GeneratedDefaultWebsocketImplementation({
channel: websocketChannel,
channelId: websocketChannelId,
Expand All @@ -374,10 +374,7 @@ export class GeneratedSdkClientClassImpl implements GeneratedSdkClientClass {
this.generatedWrappedServices = package_.subpackages.reduce<GeneratedWrappedService[]>(
(acc: GeneratedWrappedService[], wrappedSubpackageId: FernIr.SubpackageId) => {
const subpackage = this.packageResolver.resolveSubpackage(wrappedSubpackageId);
if (
subpackage.hasEndpointsInTree ||
(this.shouldGenerateWebsocketClients && subpackage.websocket != null)
) {
if (subpackage.hasEndpointsInTree || (this.generateWebSocketClients && subpackage.websocket != null)) {
acc.push(
new GeneratedWrappedService({
wrappedSubpackageId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export declare namespace SdkClientClassGenerator {
neverThrowErrors: boolean;
includeCredentialsOnCrossOriginRequests: boolean;
allowCustomFetcher: boolean;
shouldGenerateWebsocketClients: boolean;
generateWebSocketClients: boolean;
requireDefaultEnvironment: boolean;
defaultTimeoutInSeconds: number | "infinity" | undefined;
npmPackage: NpmPackage | undefined;
Expand Down Expand Up @@ -50,7 +50,7 @@ export class SdkClientClassGenerator {
private readonly neverThrowErrors: boolean;
private readonly includeCredentialsOnCrossOriginRequests: boolean;
private readonly allowCustomFetcher: boolean;
private readonly shouldGenerateWebsocketClients: boolean;
private readonly generateWebSocketClients: boolean;
private readonly requireDefaultEnvironment: boolean;
private readonly defaultTimeoutInSeconds: number | "infinity" | undefined;
private readonly npmPackage: NpmPackage | undefined;
Expand All @@ -76,7 +76,7 @@ export class SdkClientClassGenerator {
neverThrowErrors,
includeCredentialsOnCrossOriginRequests,
allowCustomFetcher,
shouldGenerateWebsocketClients,
generateWebSocketClients,
requireDefaultEnvironment,
defaultTimeoutInSeconds,
npmPackage,
Expand All @@ -101,7 +101,7 @@ export class SdkClientClassGenerator {
this.neverThrowErrors = neverThrowErrors;
this.includeCredentialsOnCrossOriginRequests = includeCredentialsOnCrossOriginRequests;
this.allowCustomFetcher = allowCustomFetcher;
this.shouldGenerateWebsocketClients = shouldGenerateWebsocketClients;
this.generateWebSocketClients = generateWebSocketClients;
this.requireDefaultEnvironment = requireDefaultEnvironment;
this.defaultTimeoutInSeconds = defaultTimeoutInSeconds;
this.npmPackage = npmPackage;
Expand Down Expand Up @@ -139,7 +139,7 @@ export class SdkClientClassGenerator {
neverThrowErrors: this.neverThrowErrors,
includeCredentialsOnCrossOriginRequests: this.includeCredentialsOnCrossOriginRequests,
allowCustomFetcher: this.allowCustomFetcher,
shouldGenerateWebsocketClients: this.shouldGenerateWebsocketClients,
generateWebSocketClients: this.generateWebSocketClients,
requireDefaultEnvironment: this.requireDefaultEnvironment,
defaultTimeoutInSeconds: this.defaultTimeoutInSeconds,
includeContentHeadersOnFileDownloadResponse: this.includeContentHeadersOnFileDownloadResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function createClientClass(opts?: {
neverThrowErrors?: boolean;
includeCredentialsOnCrossOriginRequests?: boolean;
allowCustomFetcher?: boolean;
shouldGenerateWebsocketClients?: boolean;
generateWebSocketClients?: boolean;
requireDefaultEnvironment?: boolean;
defaultTimeoutInSeconds?: number | "infinity" | undefined;
includeContentHeadersOnFileDownloadResponse?: boolean;
Expand Down Expand Up @@ -137,7 +137,7 @@ function createClientClass(opts?: {
neverThrowErrors: opts?.neverThrowErrors ?? false,
includeCredentialsOnCrossOriginRequests: opts?.includeCredentialsOnCrossOriginRequests ?? false,
allowCustomFetcher: opts?.allowCustomFetcher ?? false,
shouldGenerateWebsocketClients: opts?.shouldGenerateWebsocketClients ?? false,
generateWebSocketClients: opts?.generateWebSocketClients ?? false,
requireDefaultEnvironment: opts?.requireDefaultEnvironment ?? false,
defaultTimeoutInSeconds: opts?.defaultTimeoutInSeconds,
includeContentHeadersOnFileDownloadResponse: opts?.includeContentHeadersOnFileDownloadResponse ?? false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function createGenerator(opts?: Partial<SdkClientClassGenerator.Init>): SdkClien
neverThrowErrors: false,
includeCredentialsOnCrossOriginRequests: false,
allowCustomFetcher: false,
shouldGenerateWebsocketClients: false,
generateWebSocketClients: false,
requireDefaultEnvironment: false,
defaultTimeoutInSeconds: 60,
npmPackage: undefined,
Expand Down Expand Up @@ -127,7 +127,7 @@ describe("SdkClientClassGenerator", () => {
neverThrowErrors: true,
includeCredentialsOnCrossOriginRequests: true,
allowCustomFetcher: true,
shouldGenerateWebsocketClients: true,
generateWebSocketClients: true,
requireDefaultEnvironment: true,
includeContentHeadersOnFileDownloadResponse: true,
retainOriginalCasing: true,
Expand Down
16 changes: 8 additions & 8 deletions generators/typescript/sdk/generator/src/SdkGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export declare namespace SdkGenerator {
outputEsm: boolean;
outputJsr: boolean;
allowCustomFetcher: boolean;
shouldGenerateWebsocketClients: boolean;
generateWebSocketClients: boolean;
includeUtilsOnUnionMembers: boolean;
includeOtherInUnionTypes: boolean;
enableForwardCompatibleEnums: boolean;
Expand Down Expand Up @@ -182,7 +182,7 @@ export class SdkGenerator {
private npmPackage: NpmPackage | undefined;
private generateOAuthClients: boolean;
private generateJestTests: boolean;
private shouldGenerateWebsocketClients: boolean;
private generateWebSocketClients: boolean;
private extraFiles: Record<string, string> = {};
private extraScripts: Record<string, string> = {};

Expand Down Expand Up @@ -290,7 +290,7 @@ export class SdkGenerator {
this.generateOAuthClients =
config.generateOAuthClients &&
this.intermediateRepresentation.auth.schemes.some((scheme) => scheme.type === "oauth");
this.shouldGenerateWebsocketClients = config.shouldGenerateWebsocketClients;
this.generateWebSocketClients = config.generateWebSocketClients;

this.project = new Project({
useInMemoryFileSystem: true
Expand Down Expand Up @@ -490,7 +490,7 @@ export class SdkGenerator {
neverThrowErrors: config.neverThrowErrors,
includeCredentialsOnCrossOriginRequests: config.includeCredentialsOnCrossOriginRequests,
allowCustomFetcher: config.allowCustomFetcher,
shouldGenerateWebsocketClients: this.shouldGenerateWebsocketClients,
generateWebSocketClients: this.generateWebSocketClients,
requireDefaultEnvironment: config.requireDefaultEnvironment,
defaultTimeoutInSeconds: config.defaultTimeoutInSeconds,
npmPackage,
Expand Down Expand Up @@ -597,7 +597,7 @@ export class SdkGenerator {
this.context.logger.debug("Generated errors");
this.generateHandleNonStatusCodeError();
this.context.logger.debug("Generated handleNonStatusCodeError");
if (this.shouldGenerateWebsocketClients) {
if (this.generateWebSocketClients) {
if (this.config.includeSerdeLayer) {
this.generateUnionedResponseSchemas();
this.context.logger.debug("Generated unioned response schemas");
Expand Down Expand Up @@ -1119,7 +1119,7 @@ export class SdkGenerator {
this.context.logger.debug("Generating service declarations...");
for (const packageId of this.getAllPackageIds()) {
const package_ = this.packageResolver.resolvePackage(packageId);
if (!package_.hasEndpointsInTree && (!this.shouldGenerateWebsocketClients || package_.websocket == null)) {
if (!package_.hasEndpointsInTree && (!this.generateWebSocketClients || package_.websocket == null)) {
continue;
}
this.withSourceFile({
Expand Down Expand Up @@ -2077,7 +2077,7 @@ export class SdkGenerator {
const package_ = this.packageResolver.resolvePackage(packageId);

const hasClient =
package_.hasEndpointsInTree || (this.shouldGenerateWebsocketClients && package_.websocket != null);
package_.hasEndpointsInTree || (this.generateWebSocketClients && package_.websocket != null);

if (!hasClient && package_.subpackages.length === 0) {
continue;
Expand Down Expand Up @@ -2116,7 +2116,7 @@ export class SdkGenerator {
const package_ = this.packageResolver.resolvePackage(packageId);

const hasClient =
package_.hasEndpointsInTree || (this.shouldGenerateWebsocketClients && package_.websocket != null);
package_.hasEndpointsInTree || (this.generateWebSocketClients && package_.websocket != null);

const clientFilepath = this.sdkClientClassDeclarationReferencer.getExportedFilepath(packageId);
const clientClassName = this.sdkClientClassDeclarationReferencer.getExportedName(packageId);
Expand Down
20 changes: 20 additions & 0 deletions generators/typescript/sdk/versions.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
- version: 3.56.2
changelogEntry:
- summary: |
Rename the `shouldGenerateWebsocketClients` configuration option to
`generateWebSocketClients`. The old name is still accepted as a deprecated
fallback for backwards compatibility.
type: chore
createdAt: "2026-03-16"
irVersion: 65

- version: 3.56.1
changelogEntry:
- summary: |
Include root markdown files (README.md, reference.md, CONTRIBUTING.md) in
the output when `outputSourceFiles` is `false`. Previously, the compiled
CJS/ESM output mode only included the `dist/` directory contents, silently
dropping generated documentation files.
type: fix
createdAt: "2026-03-15"
irVersion: 65
- version: 3.56.0
changelogEntry:
- summary: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,29 @@ export class PersistedTypescriptProject {
unzipOutput?: boolean;
logger: Logger;
}): Promise<void> {
await this.zipDirectoryContents(join(this.directory, this.distDirectory), {
// Stage dist contents and root documentation files into a temp directory
// so the output zip includes them alongside the compiled cjs/esm output.
const stagingDir = AbsoluteFilePath.of((await tmp.dir()).path);
const distDir = join(this.directory, this.distDirectory);
const distItems = await readdir(distDir);
for (const item of distItems) {
await cp(join(distDir, RelativeFilePath.of(item)), join(stagingDir, RelativeFilePath.of(item)), {
recursive: true
});
}

const ROOT_FILES_TO_INCLUDE = ["README.md", "reference.md", "CONTRIBUTING.md"];
for (const filename of ROOT_FILES_TO_INCLUDE) {
const src = join(this.directory, RelativeFilePath.of(filename));
try {
await cp(src, join(stagingDir, RelativeFilePath.of(filename)));
} catch (e) {
// File may not exist (e.g. whitelabel skips CONTRIBUTING.md)
logger.debug(`Skipping ${filename}: ${e}`);
}
}

await this.zipDirectoryContents(stagingDir, {
logger,
destinationPath,
zipFilename,
Expand Down
Loading
Loading