diff --git a/packages/cli/cli/versions.yml b/packages/cli/cli/versions.yml index 16f996c5377..19926271d7a 100644 --- a/packages/cli/cli/versions.yml +++ b/packages/cli/cli/versions.yml @@ -1,3 +1,28 @@ +- changelog_entry: + - summary: | + Fixes an issue introduced in `0.41.1` that ignored server urls for docs generation. + type: fix + - summary: | + Adds a `auth-schemes` and `auth` block where you can override auth for an existing spec. + See below: + + ```generators.yml + auth-schemes: + Oauth: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.get-token + api: + auth: Oauth # overrides auth scheme + specs: + - openapi: path/to/openapi + ``` + type: feat + created_at: '2024-09-05' + ir_version: 53 + version: 0.41.2 + - changelog_entry: - summary: | Adds a V2 configuration for the `api` block that is more flexible and allows diff --git a/packages/cli/configuration/src/generators-yml/GeneratorsConfiguration.ts b/packages/cli/configuration/src/generators-yml/GeneratorsConfiguration.ts index ee06f292544..eaa1f052ed3 100644 --- a/packages/cli/configuration/src/generators-yml/GeneratorsConfiguration.ts +++ b/packages/cli/configuration/src/generators-yml/GeneratorsConfiguration.ts @@ -21,12 +21,12 @@ export interface GeneratorsConfiguration { export type APIDefinition = SingleNamespaceAPIDefinition | MultiNamespaceAPIDefinition; -export interface SingleNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema { +export interface SingleNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema, RawSchemas.WithAuthSchema { type: "singleNamespace"; definitions: APIDefinitionLocation[]; } -export interface MultiNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema { +export interface MultiNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema, RawSchemas.WithAuthSchema { type: "multiNamespace"; definitions: Record; } diff --git a/packages/cli/configuration/src/generators-yml/convertGeneratorsConfiguration.ts b/packages/cli/configuration/src/generators-yml/convertGeneratorsConfiguration.ts index 907065a5004..a97358bcdfc 100644 --- a/packages/cli/configuration/src/generators-yml/convertGeneratorsConfiguration.ts +++ b/packages/cli/configuration/src/generators-yml/convertGeneratorsConfiguration.ts @@ -33,6 +33,7 @@ import { OutputMetadataSchema } from "./schemas/OutputMetadataSchema"; import { PypiOutputMetadataSchema } from "./schemas/PypiOutputMetadataSchema"; import { ReadmeSchema } from "./schemas/ReadmeSchema"; import { ReviewersSchema } from "./schemas/ReviewersSchema"; +import { visitRawApiAuth } from "@fern-api/fern-definition-schema"; export async function convertGeneratorsConfiguration({ absolutePathToGeneratorsConfiguration, @@ -247,6 +248,24 @@ async function parseAPIConfiguration( if (apiConfiguration != null && isApiConfigurationV2Schema(apiConfiguration)) { return { type: "singleNamespace", + "auth-schemes": + apiConfiguration.auth != null + ? Object.fromEntries( + Object.entries(rawGeneratorsConfiguration["auth-schemes"] ?? {}).filter(([name, _]) => { + if (apiConfiguration.auth == null) { + return false; + } + return visitRawApiAuth(apiConfiguration.auth, { + any: (any) => { + return any.any.includes(name); + }, + single: (single) => { + return single === name; + } + }); + }) + ) + : undefined, ...apiConfiguration, definitions: apiConfiguration.specs .map((spec): APIDefinitionLocation | undefined => { diff --git a/packages/cli/configuration/src/generators-yml/schemas/APIConfigurationV2Schema.ts b/packages/cli/configuration/src/generators-yml/schemas/APIConfigurationV2Schema.ts index 2f649628e7f..97375f4cfee 100644 --- a/packages/cli/configuration/src/generators-yml/schemas/APIConfigurationV2Schema.ts +++ b/packages/cli/configuration/src/generators-yml/schemas/APIConfigurationV2Schema.ts @@ -22,5 +22,6 @@ export const SpecSchema = z.union([OpenAPISpecSchema, AsyncAPISchema]); export type SpecSchema = z.infer; export const APIConfigurationV2Schema = RawSchemas.WithEnvironmentsSchema.extend({ + auth: z.optional(RawSchemas.ApiAuthSchema), specs: z.array(SpecSchema) }); diff --git a/packages/cli/configuration/src/generators-yml/schemas/GeneratorsConfigurationSchema.ts b/packages/cli/configuration/src/generators-yml/schemas/GeneratorsConfigurationSchema.ts index 961b6281e0f..b38645c0cc0 100644 --- a/packages/cli/configuration/src/generators-yml/schemas/GeneratorsConfigurationSchema.ts +++ b/packages/cli/configuration/src/generators-yml/schemas/GeneratorsConfigurationSchema.ts @@ -1,3 +1,4 @@ +import { RawSchemas } from "@fern-api/fern-definition-schema"; import { z } from "zod"; import { APIConfigurationSchema, APIDefinitionSettingsSchema } from "./APIConfigurationSchema"; import { GeneratorGroupSchema } from "./GeneratorGroupSchema"; @@ -15,6 +16,8 @@ export const ASYNC_API_LOCATION_KEY = "async-api"; export const API_SETTINGS_KEY = "api-settings"; export const GeneratorsConfigurationSchema = z.strictObject({ + "auth-schemes": z.optional(z.record(RawSchemas.AuthSchemeDeclarationSchema)), + api: z.optional(APIConfigurationSchema), whitelabel: z.optional(WhitelabelConfigurationSchema), diff --git a/packages/cli/ete-tests/src/tests/write-definition/__snapshots__/writeDefinition.test.ts.snap b/packages/cli/ete-tests/src/tests/write-definition/__snapshots__/writeDefinition.test.ts.snap index 61c2f4411f2..c20057e07d9 100644 --- a/packages/cli/ete-tests/src/tests/write-definition/__snapshots__/writeDefinition.test.ts.snap +++ b/packages/cli/ete-tests/src/tests/write-definition/__snapshots__/writeDefinition.test.ts.snap @@ -27,6 +27,9 @@ exports[`validate > petstore 1`] = ` error-discrimination: strategy: status-code display-name: Swagger Petstore +environments: + Default: http://petstore.swagger.io/v1 +default-environment: Default ", "name": "api.yml", "type": "file", @@ -188,6 +191,9 @@ errors: error-discrimination: strategy: status-code display-name: Train Travel API +default-environment: Production +environments: + Production: https://api.example.com auth-schemes: BearerAuthScheme: scheme: bearer diff --git a/packages/cli/ete-tests/src/tests/write-definition/fixtures/namespaced/fern/.definition/api.yml b/packages/cli/ete-tests/src/tests/write-definition/fixtures/namespaced/fern/.definition/api.yml index 5850a744d19..05d3c90ddb5 100644 --- a/packages/cli/ete-tests/src/tests/write-definition/fixtures/namespaced/fern/.definition/api.yml +++ b/packages/cli/ete-tests/src/tests/write-definition/fixtures/namespaced/fern/.definition/api.yml @@ -2,6 +2,9 @@ name: api error-discrimination: strategy: status-code display-name: Train Travel API +default-environment: Production +environments: + Production: https://api.example.com auth-schemes: BearerAuthScheme: scheme: bearer diff --git a/packages/cli/ete-tests/src/tests/write-definition/fixtures/petstore/fern/.definition/api.yml b/packages/cli/ete-tests/src/tests/write-definition/fixtures/petstore/fern/.definition/api.yml index 2d4676dcd5f..54a9219768f 100644 --- a/packages/cli/ete-tests/src/tests/write-definition/fixtures/petstore/fern/.definition/api.yml +++ b/packages/cli/ete-tests/src/tests/write-definition/fixtures/petstore/fern/.definition/api.yml @@ -2,3 +2,6 @@ name: api error-discrimination: strategy: status-code display-name: Swagger Petstore +environments: + Default: http://petstore.swagger.io/v1 +default-environment: Default diff --git a/packages/cli/fern-definition/schema/src/schemas/file-schemas/RootApiFileSchema.ts b/packages/cli/fern-definition/schema/src/schemas/file-schemas/RootApiFileSchema.ts index 434b7072441..0bc6d4e1867 100644 --- a/packages/cli/fern-definition/schema/src/schemas/file-schemas/RootApiFileSchema.ts +++ b/packages/cli/fern-definition/schema/src/schemas/file-schemas/RootApiFileSchema.ts @@ -17,23 +17,31 @@ export const WithEnvironmentsSchema = z.strictObject({ export type WithEnvironmentsSchema = z.infer; -export const RootApiFileSchema = WithEnvironmentsSchema.extend({ - name: z.string(), // TODO: should this be migrated to id? - "display-name": z.optional(z.string()), - imports: z.optional(z.record(z.string())), +export const WithAuthSchema = z.strictObject({ auth: z.optional(ApiAuthSchema), - "auth-schemes": z.optional(z.record(AuthSchemeDeclarationSchema)), - headers: z.optional(z.record(z.string(), HttpHeaderSchema)), - "error-discrimination": z.optional(ErrorDiscriminationSchema), - audiences: z.optional(z.array(z.string())), - docs: z.optional(z.string()), - errors: z.optional(z.array(z.string())), - "base-path": z.optional(z.string()), - "path-parameters": z.optional(z.record(HttpPathParameterSchema)), - "idempotency-headers": z.optional(z.record(z.string(), HttpHeaderSchema)), - variables: z.optional(z.record(VariableDeclarationSchema)), - pagination: z.optional(PaginationSchema), - version: z.optional(VersionDeclarationSchema) + "auth-schemes": z.optional(z.record(AuthSchemeDeclarationSchema)) }); +export type WithAuthSchema = z.infer; + +export const RootApiFileSchema = z + .strictObject({ + name: z.string(), // TODO: should this be migrated to id? + "display-name": z.optional(z.string()), + imports: z.optional(z.record(z.string())), + headers: z.optional(z.record(z.string(), HttpHeaderSchema)), + "error-discrimination": z.optional(ErrorDiscriminationSchema), + audiences: z.optional(z.array(z.string())), + docs: z.optional(z.string()), + errors: z.optional(z.array(z.string())), + "base-path": z.optional(z.string()), + "path-parameters": z.optional(z.record(HttpPathParameterSchema)), + "idempotency-headers": z.optional(z.record(z.string(), HttpHeaderSchema)), + variables: z.optional(z.record(VariableDeclarationSchema)), + pagination: z.optional(PaginationSchema), + version: z.optional(VersionDeclarationSchema) + }) + .extend(WithEnvironmentsSchema.shape) + .extend(WithAuthSchema.shape); + export type RootApiFileSchema = z.infer; diff --git a/packages/cli/fern-definition/schema/src/schemas/file-schemas/index.ts b/packages/cli/fern-definition/schema/src/schemas/file-schemas/index.ts index 4a2621c2d48..d7e27b23b7f 100644 --- a/packages/cli/fern-definition/schema/src/schemas/file-schemas/index.ts +++ b/packages/cli/fern-definition/schema/src/schemas/file-schemas/index.ts @@ -1,3 +1,3 @@ export { DefinitionFileSchema } from "./DefinitionFileSchema"; export { PackageMarkerFileSchema } from "./PackageMarkerFileSchema"; -export { RootApiFileSchema, WithEnvironmentsSchema } from "./RootApiFileSchema"; +export { RootApiFileSchema, WithEnvironmentsSchema, WithAuthSchema } from "./RootApiFileSchema"; diff --git a/packages/cli/openapi-ir-to-fern/src/FernDefnitionBuilder.ts b/packages/cli/openapi-ir-to-fern/src/FernDefnitionBuilder.ts index cce414f67ba..3c710c2ebde 100644 --- a/packages/cli/openapi-ir-to-fern/src/FernDefnitionBuilder.ts +++ b/packages/cli/openapi-ir-to-fern/src/FernDefnitionBuilder.ts @@ -11,7 +11,7 @@ export interface FernDefinitionBuilder { addAuthScheme({ name, schema }: { name: string; schema: RawSchemas.AuthSchemeDeclarationSchema }): void; - setAuth(name: string): void; + setAuth(name: RawSchemas.ApiAuthSchema): void; getGlobalHeaderNames(): Set; @@ -138,8 +138,8 @@ export class FernDefinitionBuilderImpl implements FernDefinitionBuilder { this.rootApiFile.audiences.push(name); } - public setAuth(name: string): void { - this.rootApiFile.auth = name; + public setAuth(auth: RawSchemas.ApiAuthSchema): void { + this.rootApiFile.auth = auth; } public addAuthScheme({ name, schema }: { name: string; schema: RawSchemas.AuthSchemeDeclarationSchema }): void { diff --git a/packages/cli/openapi-ir-to-fern/src/OpenApiIrConverterContext.ts b/packages/cli/openapi-ir-to-fern/src/OpenApiIrConverterContext.ts index 2e93629489a..bace1d6b3a1 100644 --- a/packages/cli/openapi-ir-to-fern/src/OpenApiIrConverterContext.ts +++ b/packages/cli/openapi-ir-to-fern/src/OpenApiIrConverterContext.ts @@ -20,6 +20,8 @@ export interface OpenApiIrConverterContextOpts { */ detectGlobalHeaders: boolean; + authOverrides?: RawSchemas.WithAuthSchema; + environmentOverrides?: RawSchemas.WithEnvironmentsSchema; } @@ -29,6 +31,7 @@ export class OpenApiIrConverterContext { public ir: OpenApiIntermediateRepresentation; public builder: FernDefinitionBuilder; public environmentOverrides: RawSchemas.WithEnvironmentsSchema | undefined; + public authOverrides: RawSchemas.WithAuthSchema | undefined; public detectGlobalHeaders: boolean; private defaultServerName: string | undefined = undefined; @@ -37,7 +40,8 @@ export class OpenApiIrConverterContext { ir, enableUniqueErrorsPerEndpoint, detectGlobalHeaders, - environmentOverrides + environmentOverrides, + authOverrides }: OpenApiIrConverterContextOpts) { this.logger = taskContext.logger; this.taskContext = taskContext; @@ -45,6 +49,7 @@ export class OpenApiIrConverterContext { this.builder = new FernDefinitionBuilderImpl(ir, false, enableUniqueErrorsPerEndpoint); this.detectGlobalHeaders = detectGlobalHeaders; this.environmentOverrides = environmentOverrides; + this.authOverrides = authOverrides; } public getSchema(id: SchemaId): Schema | undefined { diff --git a/packages/cli/openapi-ir-to-fern/src/__test__/__snapshots__/oauth.test.ts.snap b/packages/cli/openapi-ir-to-fern/src/__test__/__snapshots__/oauth.test.ts.snap new file mode 100644 index 00000000000..2e817d9b78d --- /dev/null +++ b/packages/cli/openapi-ir-to-fern/src/__test__/__snapshots__/oauth.test.ts.snap @@ -0,0 +1,301 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`oauth > oauth > docs 1`] = ` +{ + "definitionFiles": { + "auth.yml": { + "imports": { + "root": "__package__.yml", + }, + "service": { + "auth": false, + "base-path": "", + "endpoints": { + "get-token": { + "auth": false, + "display-name": "Request an access token", + "docs": "Exchange credentials or refresh token for an access token", + "errors": [ + "root.AuthGetTokenRequestBadRequestError", + "root.AuthGetTokenRequestUnauthorizedError", + ], + "examples": [ + { + "request": { + "client_id": "client_id", + "client_secret": "client_secret", + "grant_type": "password", + }, + "response": { + "body": { + "access_token": "access_token", + "expires_in": 1, + "refresh_token": "refresh_token", + "token_type": "Bearer", + }, + }, + }, + ], + "method": "POST", + "pagination": undefined, + "path": "/oauth/token", + "request": { + "body": { + "properties": { + "client_id": { + "docs": "The client identifier", + "type": "string", + }, + "client_secret": { + "docs": "The client secret", + "type": "string", + }, + "grant_type": { + "docs": "The type of grant to request", + "type": "AuthGetTokenRequestGrantType", + }, + "password": { + "docs": "Required for password grant type", + "type": "optional", + }, + "refresh_token": { + "docs": "Required for refresh_token grant type", + "type": "optional", + }, + "username": { + "docs": "Required for password grant type", + "type": "optional", + }, + }, + }, + "headers": undefined, + "name": "AuthGetTokenRequest", + "query-parameters": undefined, + }, + "response": { + "docs": "Successful token response", + "type": "AuthGetTokenResponse", + }, + }, + }, + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + "types": { + "AuthGetTokenRequestGrantType": { + "docs": "The type of grant to request", + "enum": [ + "password", + "refresh_token", + "client_credentials", + ], + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + "AuthGetTokenResponse": { + "docs": undefined, + "properties": { + "access_token": "optional", + "expires_in": { + "docs": "Token expiration time in seconds", + "type": "optional", + }, + "refresh_token": "optional", + "token_type": "optional", + }, + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + }, + }, + }, + "packageMarkerFile": { + "errors": { + "AuthGetTokenRequestBadRequestError": { + "docs": "Bad request", + "status-code": 400, + "type": "unknown", + }, + "AuthGetTokenRequestUnauthorizedError": { + "docs": "Unauthorized", + "status-code": 401, + "type": "unknown", + }, + }, + }, + "rootApiFile": { + "auth": "OAuthScheme", + "auth-schemes": { + "OAuthScheme": { + "get-token": { + "endpoint": "auth.get_token", + }, + "scheme": "oauth", + "type": "client-credentials", + }, + }, + "default-environment": "Default", + "display-name": "OAuth Token API", + "environments": { + "Default": "https://api.example.com/v1", + }, + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, +} +`; + +exports[`oauth > oauth > simple 1`] = ` +{ + "definitionFiles": { + "auth.yml": { + "imports": { + "root": "__package__.yml", + }, + "service": { + "auth": false, + "base-path": "", + "endpoints": { + "get-token": { + "auth": false, + "display-name": "Request an access token", + "docs": "Exchange credentials or refresh token for an access token", + "errors": [ + "root.BadRequestError", + "root.UnauthorizedError", + ], + "examples": [ + { + "request": { + "client_id": "client_id", + "client_secret": "client_secret", + "grant_type": "password", + }, + "response": { + "body": { + "access_token": "access_token", + "expires_in": 1, + "refresh_token": "refresh_token", + "token_type": "Bearer", + }, + }, + }, + ], + "method": "POST", + "pagination": undefined, + "path": "/oauth/token", + "request": { + "body": { + "properties": { + "client_id": { + "docs": "The client identifier", + "type": "string", + }, + "client_secret": { + "docs": "The client secret", + "type": "string", + }, + "grant_type": { + "docs": "The type of grant to request", + "type": "AuthGetTokenRequestGrantType", + }, + "password": { + "docs": "Required for password grant type", + "type": "optional", + }, + "refresh_token": { + "docs": "Required for refresh_token grant type", + "type": "optional", + }, + "username": { + "docs": "Required for password grant type", + "type": "optional", + }, + }, + }, + "headers": undefined, + "name": "AuthGetTokenRequest", + "query-parameters": undefined, + }, + "response": { + "docs": "Successful token response", + "type": "AuthGetTokenResponse", + }, + }, + }, + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + "types": { + "AuthGetTokenRequestGrantType": { + "docs": "The type of grant to request", + "enum": [ + "password", + "refresh_token", + "client_credentials", + ], + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + "AuthGetTokenResponse": { + "docs": undefined, + "properties": { + "access_token": "optional", + "expires_in": { + "docs": "Token expiration time in seconds", + "type": "optional", + }, + "refresh_token": "optional", + "token_type": "optional", + }, + "source": { + "openapi": "oauth/openapi.yml", + }, + }, + }, + }, + }, + "packageMarkerFile": { + "errors": { + "BadRequestError": { + "docs": "Bad request", + "status-code": 400, + "type": "unknown", + }, + "UnauthorizedError": { + "docs": "Unauthorized", + "status-code": 401, + "type": "unknown", + }, + }, + }, + "rootApiFile": { + "auth": "OAuthScheme", + "auth-schemes": { + "OAuthScheme": { + "get-token": { + "endpoint": "auth.get_token", + }, + "scheme": "oauth", + "type": "client-credentials", + }, + }, + "default-environment": "Default", + "display-name": "OAuth Token API", + "environments": { + "Default": "https://api.example.com/v1", + }, + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, +} +`; diff --git a/packages/cli/openapi-ir-to-fern/src/__test__/fixtures/oauth/openapi.yml b/packages/cli/openapi-ir-to-fern/src/__test__/fixtures/oauth/openapi.yml new file mode 100644 index 00000000000..a0f72074544 --- /dev/null +++ b/packages/cli/openapi-ir-to-fern/src/__test__/fixtures/oauth/openapi.yml @@ -0,0 +1,80 @@ +openapi: 3.0.0 +info: + title: OAuth Token API + version: 1.0.0 + description: A simple API with an OAuth token endpoint accepting JSON input + +servers: + - url: https://api.example.com/v1 + +paths: + /oauth/token: + post: + x-fern-sdk-group-name: auth + x-fern-sdk-method-name: get-token + summary: Request an access token + description: Exchange credentials or refresh token for an access token + tags: + - OAuth + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + grant_type: + type: string + enum: [password, refresh_token, client_credentials] + description: The type of grant to request + username: + type: string + description: Required for password grant type + password: + type: string + description: Required for password grant type + refresh_token: + type: string + description: Required for refresh_token grant type + client_id: + type: string + description: The client identifier + client_secret: + type: string + description: The client secret + required: + - grant_type + - client_id + - client_secret + responses: + '200': + description: Successful token response + content: + application/json: + schema: + type: object + properties: + access_token: + type: string + token_type: + type: string + example: "Bearer" + expires_in: + type: integer + description: Token expiration time in seconds + refresh_token: + type: string + '400': + description: Bad request + '401': + description: Unauthorized + +components: + securitySchemes: + oauth2: + type: oauth2 + flows: + password: + tokenUrl: /oauth/token + clientCredentials: + tokenUrl: /oauth/token \ No newline at end of file diff --git a/packages/cli/openapi-ir-to-fern/src/__test__/oauth.test.ts b/packages/cli/openapi-ir-to-fern/src/__test__/oauth.test.ts new file mode 100644 index 00000000000..210e3720537 --- /dev/null +++ b/packages/cli/openapi-ir-to-fern/src/__test__/oauth.test.ts @@ -0,0 +1,18 @@ +import { testConvertOpenAPI } from "./testConvertOpenApi"; + +describe("oauth", () => { + testConvertOpenAPI("oauth", "openapi.yml", { + authOverrides: { + auth: "OAuthScheme", + "auth-schemes": { + OAuthScheme: { + scheme: "oauth", + type: "client-credentials", + "get-token": { + endpoint: "auth.get_token" + } + } + } + } + }); +}); diff --git a/packages/cli/openapi-ir-to-fern/src/__test__/testConvertOpenApi.ts b/packages/cli/openapi-ir-to-fern/src/__test__/testConvertOpenApi.ts index eab954c487d..93923942bb1 100644 --- a/packages/cli/openapi-ir-to-fern/src/__test__/testConvertOpenApi.ts +++ b/packages/cli/openapi-ir-to-fern/src/__test__/testConvertOpenApi.ts @@ -13,6 +13,7 @@ export declare namespace TestConvertOpenAPI { interface Options { asyncApiFilename?: string; environmentOverrides?: RawSchemas.WithEnvironmentsSchema; + authOverrides?: RawSchemas.WithAuthSchema; } } @@ -56,6 +57,7 @@ export function testConvertOpenAPI(fixtureName: string, filename: string, opts: }); const fernDefinition = convert({ environmentOverrides: opts.environmentOverrides, + authOverrides: opts.authOverrides, ir: openApiIr, taskContext: mockTaskContext, enableUniqueErrorsPerEndpoint: false, @@ -100,6 +102,7 @@ export function testConvertOpenAPI(fixtureName: string, filename: string, opts: }); const fernDefinition = convert({ environmentOverrides: opts.environmentOverrides, + authOverrides: opts.authOverrides, ir: openApiIr, taskContext: mockTaskContext, enableUniqueErrorsPerEndpoint: true, diff --git a/packages/cli/openapi-ir-to-fern/src/buildAuthSchemes.ts b/packages/cli/openapi-ir-to-fern/src/buildAuthSchemes.ts index 4988cbfe945..777f0e59bb9 100644 --- a/packages/cli/openapi-ir-to-fern/src/buildAuthSchemes.ts +++ b/packages/cli/openapi-ir-to-fern/src/buildAuthSchemes.ts @@ -8,6 +8,19 @@ const BASIC_AUTH_SCHEME = "BasicAuthScheme"; const BEARER_AUTH_SCHEME = "BearerAuthScheme"; export function buildAuthSchemes(context: OpenApiIrConverterContext): void { + if (context.authOverrides != null) { + for (const [name, declaration] of Object.entries(context.authOverrides["auth-schemes"] ?? {})) { + context.builder.addAuthScheme({ + name, + schema: declaration + }); + } + if (context.authOverrides.auth != null) { + context.builder.setAuth(context.authOverrides.auth); + } + return; + } + let setAuth = false; for (const [id, securityScheme] of Object.entries(context.ir.securitySchemes)) { diff --git a/packages/cli/workspace-loader/src/workspaces/OSSWorkspace.ts b/packages/cli/workspace-loader/src/workspaces/OSSWorkspace.ts index bbec8dd46ee..8918ec6336d 100644 --- a/packages/cli/workspace-loader/src/workspaces/OSSWorkspace.ts +++ b/packages/cli/workspace-loader/src/workspaces/OSSWorkspace.ts @@ -1,10 +1,9 @@ import { FERN_PACKAGE_MARKER_FILENAME, generatorsYml } from "@fern-api/configuration"; import { isNonNullish } from "@fern-api/core-utils"; import { AbsoluteFilePath, RelativeFilePath } from "@fern-api/fs-utils"; -import { convert, OpenApiConvertedFernDefinition } from "@fern-api/openapi-ir-to-fern"; +import { convert } from "@fern-api/openapi-ir-to-fern"; import { parse, ParseOpenAPIOptions } from "@fern-api/openapi-parser"; import { TaskContext } from "@fern-api/task-context"; -import { isRawProtobufSourceSchema } from "@fern-api/fern-definition-schema"; import yaml from "js-yaml"; import { mapValues as mapValuesLodash } from "lodash-es"; import { v4 as uuidv4 } from "uuid"; @@ -83,9 +82,12 @@ export class OSSWorkspace extends AbstractAPIWorkspace { // file paths with the inputted namespace, however given auth and other shared settings I think we have to // resolve to the IR first, and namespace there. const definition = convert({ - environmentOverrides: { - ...this.generatorsConfiguration?.api - }, + authOverrides: + this.generatorsConfiguration?.api?.auth != null ? { ...this.generatorsConfiguration?.api } : undefined, + environmentOverrides: + this.generatorsConfiguration?.api?.environments != null + ? { ...this.generatorsConfiguration?.api } + : undefined, taskContext: context, ir: openApiIr, enableUniqueErrorsPerEndpoint: settings?.enableUniqueErrorsPerEndpoint ?? false,