diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-request.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-request.json new file mode 100644 index 000000000000..314842d4eb86 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-request.json @@ -0,0 +1,139 @@ +{ + "specVersion": "1.0.0", + "title": "OAuth scope inline request", + "servers": [], + "websocketServers": [], + "tags": { + "tagsById": {} + }, + "hasEndpointsMarkedInternal": false, + "endpoints": [ + { + "audiences": [], + "operationId": "createScope", + "tags": [], + "pathParameters": [], + "queryParameters": [], + "headers": [], + "generatedRequestName": "CreateScopeRequest", + "request": { + "schema": { + "generatedName": "CreateScopeRequest", + "schema": "OAuthScope", + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "reference" + }, + "contentType": "application/json", + "required": true, + "fullExamples": [], + "additionalProperties": false, + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "json" + }, + "errors": {}, + "servers": [], + "authed": true, + "security": [ + { + "OAuth2": [ + "read" + ] + } + ], + "method": "POST", + "path": "/scope", + "examples": [ + { + "pathParameters": [], + "queryParameters": [], + "headers": [], + "request": { + "properties": { + "value": { + "value": { + "value": "value", + "type": "string" + }, + "type": "primitive" + } + }, + "type": "object" + }, + "codeSamples": [], + "type": "full" + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + } + } + ], + "webhooks": [], + "channels": {}, + "groupedSchemas": { + "rootSchemas": { + "OAuthScope": { + "allOf": [], + "properties": [ + { + "conflict": {}, + "generatedName": "oAuthScopeValue", + "key": "value", + "schema": { + "schema": { + "type": "string" + }, + "generatedName": "OAuthScopeValue", + "groupName": [], + "type": "primitive" + }, + "audiences": [] + } + ], + "allOfPropertyConflicts": [], + "generatedName": "OAuthScope", + "groupName": [], + "additionalProperties": false, + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "object" + } + }, + "namespacedSchemas": {} + }, + "variables": {}, + "nonRequestReferencedSchemas": {}, + "securitySchemes": { + "OAuth2": { + "scopesEnum": { + "generatedName": "OauthScope", + "values": [ + { + "generatedName": "read", + "value": "read", + "description": "Read access", + "casing": {} + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "enum" + }, + "type": "oauth" + } + }, + "globalHeaders": [], + "idempotencyHeaders": [], + "groups": {} +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-type.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-type.json new file mode 100644 index 000000000000..d36f61a9a03a --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-inline-type.json @@ -0,0 +1,135 @@ +{ + "specVersion": "1.0.0", + "title": "OAuth scope inline type", + "servers": [], + "websocketServers": [], + "tags": { + "tagsById": {} + }, + "hasEndpointsMarkedInternal": false, + "endpoints": [ + { + "audiences": [], + "operationId": "createScope", + "tags": [], + "pathParameters": [], + "queryParameters": [], + "headers": [], + "generatedRequestName": "CreateScopeRequest", + "request": { + "schema": { + "allOf": [], + "properties": [ + { + "conflict": {}, + "generatedName": "createScopeRequestScope", + "key": "scope", + "schema": { + "generatedName": "CreateScopeRequestScope", + "nameOverride": "OAuthScope", + "values": [ + { + "generatedName": "account", + "value": "account", + "casing": {} + } + ], + "groupName": [], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "enum" + }, + "audiences": [] + } + ], + "allOfPropertyConflicts": [], + "generatedName": "CreateScopeRequest", + "groupName": [], + "additionalProperties": false, + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "object" + }, + "contentType": "application/json", + "required": true, + "fullExamples": [], + "additionalProperties": false, + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "json" + }, + "errors": {}, + "servers": [], + "authed": true, + "security": [ + { + "OAuth2": [ + "read" + ] + } + ], + "method": "POST", + "path": "/scope", + "examples": [ + { + "pathParameters": [], + "queryParameters": [], + "headers": [], + "request": { + "properties": { + "scope": { + "value": "account", + "type": "enum" + } + }, + "type": "object" + }, + "codeSamples": [], + "type": "full" + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + } + } + ], + "webhooks": [], + "channels": {}, + "groupedSchemas": { + "rootSchemas": {}, + "namespacedSchemas": {} + }, + "variables": {}, + "nonRequestReferencedSchemas": {}, + "securitySchemes": { + "OAuth2": { + "scopesEnum": { + "generatedName": "OauthScope", + "values": [ + { + "generatedName": "read", + "value": "read", + "description": "Read access", + "casing": {} + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "enum" + }, + "type": "oauth" + } + }, + "globalHeaders": [], + "idempotencyHeaders": [], + "groups": {} +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-name-collision.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-name-collision.json new file mode 100644 index 000000000000..123af02114c0 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-name-collision.json @@ -0,0 +1,190 @@ +{ + "specVersion": "1.0.0", + "title": "OAuth scope name collision", + "servers": [], + "websocketServers": [], + "tags": { + "tagsById": {} + }, + "hasEndpointsMarkedInternal": false, + "endpoints": [ + { + "audiences": [], + "operationId": "getScope", + "tags": [], + "pathParameters": [], + "queryParameters": [], + "headers": [], + "generatedRequestName": "GetScopeRequest", + "response": { + "description": "Success", + "schema": { + "generatedName": "GetScopeResponse", + "schema": "OAuthScope", + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "reference" + }, + "fullExamples": [], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "statusCode": 200, + "type": "json" + }, + "errors": {}, + "servers": [], + "authed": true, + "security": [ + { + "OAuth2": [ + "read" + ] + } + ], + "method": "GET", + "path": "/scope", + "examples": [ + { + "pathParameters": [], + "queryParameters": [], + "headers": [], + "response": { + "value": { + "value": { + "value": "string", + "type": "string" + }, + "type": "primitive" + }, + "type": "withoutStreaming" + }, + "codeSamples": [], + "type": "full" + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + } + }, + { + "audiences": [], + "operationId": "getGroupedScope", + "tags": [], + "pathParameters": [], + "queryParameters": [], + "headers": [], + "generatedRequestName": "GetGroupedScopeRequest", + "response": { + "description": "Success", + "schema": { + "generatedName": "GetGroupedScopeResponse", + "schema": "OauthAuthorizationScope2", + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "reference" + }, + "fullExamples": [], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "statusCode": 200, + "type": "json" + }, + "errors": {}, + "servers": [], + "authed": false, + "method": "GET", + "path": "/grouped", + "examples": [ + { + "pathParameters": [], + "queryParameters": [], + "headers": [], + "response": { + "value": { + "value": { + "value": "string", + "type": "string" + }, + "type": "primitive" + }, + "type": "withoutStreaming" + }, + "codeSamples": [], + "type": "full" + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + } + } + ], + "webhooks": [], + "channels": {}, + "groupedSchemas": { + "rootSchemas": { + "OAuthScope": { + "schema": { + "type": "string" + }, + "generatedName": "OAuthScope", + "groupName": [], + "type": "primitive" + }, + "OauthAuthorizationScope": { + "schema": { + "type": "string" + }, + "generatedName": "OauthAuthorizationScope", + "groupName": [], + "type": "primitive" + }, + "OauthAuthorizationScope2": { + "schema": { + "type": "string" + }, + "generatedName": "OauthAuthorizationScope2", + "groupName": [ + "grouped" + ], + "type": "primitive" + } + }, + "namespacedSchemas": {} + }, + "variables": {}, + "nonRequestReferencedSchemas": {}, + "securitySchemes": { + "OAuth2": { + "scopesEnum": { + "generatedName": "OauthScope", + "values": [ + { + "generatedName": "read", + "value": "read", + "description": "Read access", + "casing": {} + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "enum" + }, + "type": "oauth" + } + }, + "globalHeaders": [], + "idempotencyHeaders": [], + "groups": {} +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-webhook-response.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-webhook-response.json new file mode 100644 index 000000000000..294458a28f29 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi-ir/oauth-scope-webhook-response.json @@ -0,0 +1,125 @@ +{ + "specVersion": "1.0.0", + "title": "OAuth scope webhook response", + "servers": [], + "websocketServers": [], + "tags": { + "tagsById": {} + }, + "hasEndpointsMarkedInternal": false, + "endpoints": [], + "webhooks": [ + { + "audiences": [], + "method": "POST", + "operationId": "updateStatus", + "tags": [], + "headers": [], + "generatedPayloadName": "UpdateStatusPayload", + "payload": { + "allOf": [], + "properties": [ + { + "conflict": {}, + "generatedName": "updateStatusPayloadStatus", + "key": "status", + "schema": { + "generatedName": "UpdateStatusPayloadStatus", + "value": { + "schema": { + "type": "string" + }, + "generatedName": "UpdateStatusPayloadStatus", + "groupName": [], + "type": "primitive" + }, + "groupName": [], + "type": "optional" + }, + "audiences": [] + } + ], + "allOfPropertyConflicts": [], + "generatedName": "UpdateStatusPayload", + "groupName": [], + "additionalProperties": false, + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "object" + }, + "response": { + "description": "Success", + "schema": { + "generatedName": "UpdateStatusResponse", + "schema": "OAuthScope", + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "reference" + }, + "fullExamples": [], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "statusCode": 200, + "type": "json" + }, + "examples": [ + { + "payload": { + "properties": {}, + "type": "object" + } + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + } + } + ], + "channels": {}, + "groupedSchemas": { + "rootSchemas": { + "OAuthScope": { + "schema": { + "type": "string" + }, + "generatedName": "OAuthScope", + "groupName": [], + "type": "primitive" + } + }, + "namespacedSchemas": {} + }, + "variables": {}, + "nonRequestReferencedSchemas": {}, + "securitySchemes": { + "OAuth2": { + "scopesEnum": { + "generatedName": "OauthScope", + "values": [ + { + "generatedName": "read", + "value": "read", + "description": "Read access", + "casing": {} + } + ], + "source": { + "file": "../openapi.yml", + "type": "openapi" + }, + "type": "enum" + }, + "type": "oauth" + } + }, + "globalHeaders": [], + "idempotencyHeaders": [], + "groups": {} +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-request.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-request.json new file mode 100644 index 000000000000..82190698aa3f --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-request.json @@ -0,0 +1,127 @@ +{ + "absoluteFilePath": "/DUMMY_PATH", + "importedDefinitions": {}, + "namedDefinitionFiles": { + "__package__.yml": { + "absoluteFilepath": "/DUMMY_PATH", + "contents": { + "service": { + "auth": false, + "base-path": "", + "endpoints": { + "createScope": { + "auth": [ + { + "OAuth2": [ + "read", + ], + }, + ], + "docs": undefined, + "examples": [ + { + "request": { + "value": "value", + }, + }, + ], + "method": "POST", + "pagination": undefined, + "path": "/scope", + "request": { + "body": { + "properties": { + "value": "string", + }, + }, + "content-type": "application/json", + "headers": undefined, + "name": "OAuthScope", + "path-parameters": undefined, + "query-parameters": undefined, + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + "types": { + "OauthScope": { + "enum": [ + { + "docs": "Read access", + "value": "read", + }, + ], + "inline": undefined, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + }, + "rawContents": "types: + OauthScope: + enum: + - value: read + docs: Read access + source: + openapi: ../openapi.yml +service: + auth: false + base-path: '' + endpoints: + createScope: + path: /scope + method: POST + auth: + - OAuth2: + - read + source: + openapi: ../openapi.yml + request: + name: OAuthScope + body: + properties: + value: string + content-type: application/json + examples: + - request: + value: value + source: + openapi: ../openapi.yml +", + }, + }, + "packageMarkers": {}, + "rootApiFile": { + "contents": { + "auth": "OAuth2", + "auth-schemes": { + "OAuth2": { + "scheme": "bearer", + }, + }, + "display-name": "OAuth scope inline request", + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, + "defaultUrl": undefined, + "rawContents": "name: api +error-discrimination: + strategy: status-code +display-name: OAuth scope inline request +auth-schemes: + OAuth2: + scheme: bearer +auth: OAuth2 +", + }, + "specVersion": "1.0.0", +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-type.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-type.json new file mode 100644 index 000000000000..c7d7f679f201 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-inline-type.json @@ -0,0 +1,142 @@ +{ + "absoluteFilePath": "/DUMMY_PATH", + "importedDefinitions": {}, + "namedDefinitionFiles": { + "__package__.yml": { + "absoluteFilepath": "/DUMMY_PATH", + "contents": { + "service": { + "auth": false, + "base-path": "", + "endpoints": { + "createScope": { + "auth": [ + { + "OAuth2": [ + "read", + ], + }, + ], + "docs": undefined, + "examples": [ + { + "request": { + "scope": "account", + }, + }, + ], + "method": "POST", + "pagination": undefined, + "path": "/scope", + "request": { + "body": { + "properties": { + "scope": "OAuthScope", + }, + }, + "content-type": "application/json", + "headers": undefined, + "name": "CreateScopeRequest", + "path-parameters": undefined, + "query-parameters": undefined, + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + "types": { + "OAuthScope": { + "enum": [ + "account", + ], + "inline": true, + "source": { + "openapi": "../openapi.yml", + }, + }, + "OauthAuthorizationScope": { + "enum": [ + { + "docs": "Read access", + "value": "read", + }, + ], + "inline": undefined, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + }, + "rawContents": "types: + OauthAuthorizationScope: + enum: + - value: read + docs: Read access + source: + openapi: ../openapi.yml + OAuthScope: + enum: + - account + inline: true + source: + openapi: ../openapi.yml +service: + auth: false + base-path: '' + endpoints: + createScope: + path: /scope + method: POST + auth: + - OAuth2: + - read + source: + openapi: ../openapi.yml + request: + name: CreateScopeRequest + body: + properties: + scope: OAuthScope + content-type: application/json + examples: + - request: + scope: account + source: + openapi: ../openapi.yml +", + }, + }, + "packageMarkers": {}, + "rootApiFile": { + "contents": { + "auth": "OAuth2", + "auth-schemes": { + "OAuth2": { + "scheme": "bearer", + }, + }, + "display-name": "OAuth scope inline type", + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, + "defaultUrl": undefined, + "rawContents": "name: api +error-discrimination: + strategy: status-code +display-name: OAuth scope inline type +auth-schemes: + OAuth2: + scheme: bearer +auth: OAuth2 +", + }, + "specVersion": "1.0.0", +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-name-collision.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-name-collision.json new file mode 100644 index 000000000000..314eb06a6844 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-name-collision.json @@ -0,0 +1,170 @@ +{ + "absoluteFilePath": "/DUMMY_PATH", + "importedDefinitions": {}, + "namedDefinitionFiles": { + "__package__.yml": { + "absoluteFilepath": "/DUMMY_PATH", + "contents": { + "imports": { + "grouped": "grouped.yml", + }, + "service": { + "auth": false, + "base-path": "", + "endpoints": { + "getGroupedScope": { + "auth": undefined, + "docs": undefined, + "examples": [ + { + "response": { + "body": "string", + }, + }, + ], + "method": "GET", + "pagination": undefined, + "path": "/grouped", + "response": { + "docs": "Success", + "status-code": 200, + "type": "grouped.OauthAuthorizationScope2", + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + "getScope": { + "auth": [ + { + "OAuth2": [ + "read", + ], + }, + ], + "docs": undefined, + "examples": [ + { + "response": { + "body": "string", + }, + }, + ], + "method": "GET", + "pagination": undefined, + "path": "/scope", + "response": { + "docs": "Success", + "status-code": 200, + "type": "OAuthScope", + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + "types": { + "OAuthScope": "string", + "OauthAuthorizationScope": { + "enum": [ + { + "docs": "Read access", + "value": "read", + }, + ], + "inline": undefined, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + }, + "rawContents": "types: + OauthAuthorizationScope: + enum: + - value: read + docs: Read access + source: + openapi: ../openapi.yml + OAuthScope: string +service: + auth: false + base-path: '' + endpoints: + getScope: + path: /scope + method: GET + auth: + - OAuth2: + - read + source: + openapi: ../openapi.yml + response: + docs: Success + type: OAuthScope + status-code: 200 + examples: + - response: + body: string + getGroupedScope: + path: /grouped + method: GET + source: + openapi: ../openapi.yml + response: + docs: Success + type: grouped.OauthAuthorizationScope2 + status-code: 200 + examples: + - response: + body: string + source: + openapi: ../openapi.yml +imports: + grouped: grouped.yml +", + }, + "grouped.yml": { + "absoluteFilepath": "/DUMMY_PATH", + "contents": { + "types": { + "OauthAuthorizationScope2": "string", + }, + }, + "rawContents": "types: + OauthAuthorizationScope2: string +", + }, + }, + "packageMarkers": {}, + "rootApiFile": { + "contents": { + "auth": "OAuth2", + "auth-schemes": { + "OAuth2": { + "scheme": "bearer", + }, + }, + "display-name": "OAuth scope name collision", + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, + "defaultUrl": undefined, + "rawContents": "name: api +error-discrimination: + strategy: status-code +display-name: OAuth scope name collision +auth-schemes: + OAuth2: + scheme: bearer +auth: OAuth2 +", + }, + "specVersion": "1.0.0", +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-webhook-response.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-webhook-response.json new file mode 100644 index 000000000000..45cb8c259081 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/__snapshots__/openapi/oauth-scope-webhook-response.json @@ -0,0 +1,111 @@ +{ + "absoluteFilePath": "/DUMMY_PATH", + "importedDefinitions": {}, + "namedDefinitionFiles": { + "__package__.yml": { + "absoluteFilepath": "/DUMMY_PATH", + "contents": { + "types": { + "OAuthScope": "string", + "OauthAuthorizationScope": { + "enum": [ + { + "docs": "Read access", + "value": "read", + }, + ], + "inline": undefined, + "source": { + "openapi": "../openapi.yml", + }, + }, + "UpdateStatusPayload": { + "docs": undefined, + "inline": undefined, + "properties": { + "status": "optional", + }, + "source": { + "openapi": "../openapi.yml", + }, + }, + }, + "webhooks": { + "updateStatus": { + "audiences": [], + "display-name": undefined, + "examples": [ + { + "docs": undefined, + "name": undefined, + "payload": {}, + }, + ], + "headers": {}, + "method": "POST", + "payload": "UpdateStatusPayload", + "response": { + "docs": "Success", + "status-code": 200, + "type": "OAuthScope", + }, + "signature": undefined, + }, + }, + }, + "rawContents": "types: + OauthAuthorizationScope: + enum: + - value: read + docs: Read access + source: + openapi: ../openapi.yml + UpdateStatusPayload: + properties: + status: optional + source: + openapi: ../openapi.yml + OAuthScope: string +webhooks: + updateStatus: + audiences: [] + method: POST + headers: {} + payload: UpdateStatusPayload + examples: + - payload: {} + response: + docs: Success + type: OAuthScope + status-code: 200 +", + }, + }, + "packageMarkers": {}, + "rootApiFile": { + "contents": { + "auth": "OAuth2", + "auth-schemes": { + "OAuth2": { + "scheme": "bearer", + }, + }, + "display-name": "OAuth scope webhook response", + "error-discrimination": { + "strategy": "status-code", + }, + "name": "api", + }, + "defaultUrl": undefined, + "rawContents": "name: api +error-discrimination: + strategy: status-code +display-name: OAuth scope webhook response +auth-schemes: + OAuth2: + scheme: bearer +auth: OAuth2 +", + }, + "specVersion": "1.0.0", +} \ No newline at end of file diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/fern.config.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/fern.config.json new file mode 100644 index 000000000000..ecb7133e2645 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "fern", + "version": "*" +} diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/generators.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/generators.yml new file mode 100644 index 000000000000..68e124f7ee12 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/fern/generators.yml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json +api: + specs: + - openapi: ../openapi.yml + settings: + only-include-referenced-schemas: true diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/openapi.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/openapi.yml new file mode 100644 index 000000000000..f376488681c2 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-request/openapi.yml @@ -0,0 +1,40 @@ +openapi: 3.0.3 +info: + title: OAuth scope inline request + version: 1.0.0 + +paths: + /scope: + post: + operationId: createScope + security: + - OAuth2: + - read + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/OAuthScope" + responses: + "204": + description: Success + +components: + schemas: + OAuthScope: + type: object + required: + - value + properties: + value: + type: string + + securitySchemes: + OAuth2: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://example.com/oauth/token + scopes: + read: Read access diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/fern.config.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/fern.config.json new file mode 100644 index 000000000000..ecb7133e2645 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "fern", + "version": "*" +} diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/generators.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/generators.yml new file mode 100644 index 000000000000..5b01f1e0833d --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/fern/generators.yml @@ -0,0 +1,4 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json +api: + specs: + - openapi: ../openapi.yml diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/openapi.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/openapi.yml new file mode 100644 index 000000000000..653fa145caf5 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-inline-type/openapi.yml @@ -0,0 +1,39 @@ +openapi: 3.0.3 +info: + title: OAuth scope inline type + version: 1.0.0 + +paths: + /scope: + post: + operationId: createScope + security: + - OAuth2: + - read + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - scope + properties: + scope: + type: string + enum: + - account + x-fern-type-name: OAuthScope + responses: + "204": + description: Success + +components: + securitySchemes: + OAuth2: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://example.com/oauth/token + scopes: + read: Read access diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/fern.config.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/fern.config.json new file mode 100644 index 000000000000..ecb7133e2645 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "fern", + "version": "*" +} diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/generators.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/generators.yml new file mode 100644 index 000000000000..68e124f7ee12 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/fern/generators.yml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json +api: + specs: + - openapi: ../openapi.yml + settings: + only-include-referenced-schemas: true diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/openapi.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/openapi.yml new file mode 100644 index 000000000000..bf199b728d1c --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-name-collision/openapi.yml @@ -0,0 +1,48 @@ +openapi: 3.0.3 +info: + title: OAuth scope name collision + version: 1.0.0 + +paths: + /scope: + get: + operationId: getScope + security: + - OAuth2: + - read + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/OAuthScope" + /grouped: + get: + operationId: getGroupedScope + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/OauthAuthorizationScope2" + +components: + schemas: + OAuthScope: + type: string + OauthAuthorizationScope: + type: string + OauthAuthorizationScope2: + type: string + x-fern-sdk-group-name: grouped + + securitySchemes: + OAuth2: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://example.com/oauth/token + scopes: + read: Read access diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/fern.config.json b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/fern.config.json new file mode 100644 index 000000000000..ecb7133e2645 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "fern", + "version": "*" +} diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/generators.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/generators.yml new file mode 100644 index 000000000000..68e124f7ee12 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/fern/generators.yml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json +api: + specs: + - openapi: ../openapi.yml + settings: + only-include-referenced-schemas: true diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/openapi.yml b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/openapi.yml new file mode 100644 index 000000000000..1248537d3f84 --- /dev/null +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern-tests/src/__test__/fixtures/oauth-scope-webhook-response/openapi.yml @@ -0,0 +1,41 @@ +openapi: 3.1.0 +info: + title: OAuth scope webhook response + version: 1.0.0 + +paths: {} + +webhooks: + status: + post: + operationId: updateStatus + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + status: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/OAuthScope" + +components: + schemas: + OAuthScope: + type: string + + securitySchemes: + OAuth2: + type: oauth2 + flows: + clientCredentials: + tokenUrl: https://example.com/oauth/token + scopes: + read: Read access diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildAuthSchemes.ts b/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildAuthSchemes.ts index 456829f197d5..3ef09797ff16 100644 --- a/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildAuthSchemes.ts +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildAuthSchemes.ts @@ -1,13 +1,15 @@ import { RawSchemas } from "@fern-api/fern-definition-schema"; -import { RelativeFilePath } from "@fern-api/path-utils"; +import type { FernDefinition } from "@fern-api/importer-commons"; import { buildEnumTypeDeclaration } from "./buildTypeDeclaration.js"; import { OpenApiIrConverterContext } from "./OpenApiIrConverterContext.js"; import { getHeaderName } from "./utils/getHeaderName.js"; const BASIC_AUTH_SCHEME = "BasicAuthScheme"; const BEARER_AUTH_SCHEME = "BearerAuthScheme"; +const OAUTH_SCOPE_TYPE_NAME = "OauthScope"; +const OAUTH_SCOPE_FALLBACK_TYPE_NAME = "OauthAuthorizationScope"; -export function buildAuthSchemes(context: OpenApiIrConverterContext): void { +export function buildAuthSchemes(context: OpenApiIrConverterContext): RawSchemas.TypeDeclarationSchema | undefined { if (context.authOverrides != null) { for (const [name, declaration] of Object.entries(context.authOverrides["auth-schemes"] ?? {})) { context.builder.addAuthScheme({ @@ -18,11 +20,11 @@ export function buildAuthSchemes(context: OpenApiIrConverterContext): void { if (context.authOverrides.auth != null) { context.builder.setAuth(context.authOverrides.auth); } - return; + return undefined; } let setAuth = false; - + let oauthScopeType: RawSchemas.TypeDeclarationSchema | undefined; for (const [id, securityScheme] of Object.entries(context.ir.securitySchemes)) { if (securityScheme.type === "basic") { const basicAuthScheme: RawSchemas.BasicAuthSchemeSchema = { @@ -179,11 +181,43 @@ export function buildAuthSchemes(context: OpenApiIrConverterContext): void { setAuth = true; } if (securityScheme.scopesEnum != null && securityScheme.scopesEnum.values.length > 0) { - context.builder.addType(RelativeFilePath.of("__package__.yml"), { - name: "OauthScope", - schema: buildEnumTypeDeclaration(securityScheme.scopesEnum, 0).schema - }); + // Preserve the existing behavior for multiple OAuth schemes: the last non-empty scope enum wins. + oauthScopeType = buildEnumTypeDeclaration(securityScheme.scopesEnum, 0).schema; } } } + return oauthScopeType; +} + +/** + * Adds the OAuth scope enum after all other types have been built, so its name can be deconflicted against the + * declarations that were actually emitted rather than a parallel approximation. + */ +export function addOauthScopeType(definition: FernDefinition, oauthScopeType: RawSchemas.TypeDeclarationSchema): void { + const existingTypes = definition.packageMarkerFile.types ?? {}; + const oauthScopeTypeName = getOauthScopeTypeName(Object.keys(existingTypes)); + const { types: _, ...packageMarkerFile } = definition.packageMarkerFile; + definition.packageMarkerFile = { + types: { + [oauthScopeTypeName]: oauthScopeType, + ...existingTypes + }, + ...packageMarkerFile + }; +} + +function getOauthScopeTypeName(typeNames: Iterable): string { + const occupiedTypeNames = new Set([...typeNames].map((name) => name.toLowerCase())); + if (!occupiedTypeNames.has(OAUTH_SCOPE_TYPE_NAME.toLowerCase())) { + return OAUTH_SCOPE_TYPE_NAME; + } + if (!occupiedTypeNames.has(OAUTH_SCOPE_FALLBACK_TYPE_NAME.toLowerCase())) { + return OAUTH_SCOPE_FALLBACK_TYPE_NAME; + } + + let suffix = 2; + while (occupiedTypeNames.has(`${OAUTH_SCOPE_FALLBACK_TYPE_NAME}${suffix}`.toLowerCase())) { + suffix++; + } + return `${OAUTH_SCOPE_FALLBACK_TYPE_NAME}${suffix}`; } diff --git a/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildFernDefinition.ts b/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildFernDefinition.ts index 9e8316e11b0b..180eee936b92 100644 --- a/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildFernDefinition.ts +++ b/packages/cli/api-importers/openapi/openapi-ir-to-fern/src/buildFernDefinition.ts @@ -3,7 +3,7 @@ import { isRawAliasDefinition, RawSchemas } from "@fern-api/fern-definition-sche import { FernDefinition } from "@fern-api/importer-commons"; import { Schema } from "@fern-api/openapi-ir"; import { RelativeFilePath } from "@fern-api/path-utils"; -import { buildAuthSchemes } from "./buildAuthSchemes.js"; +import { addOauthScopeType, buildAuthSchemes } from "./buildAuthSchemes.js"; import { buildChannel } from "./buildChannel.js"; import { buildEnvironments } from "./buildEnvironments.js"; import { buildGlobalHeaders } from "./buildGlobalHeaders.js"; @@ -145,7 +145,7 @@ export function buildFernDefinition(context: OpenApiIrConverterContext): FernDef buildGlobalHeaders(context); buildGlobalParameters(context); buildIdempotencyHeaders(context); - buildAuthSchemes(context); + const oauthScopeType = buildAuthSchemes(context); buildVariables(context); if (context.ir.basePath != null) { context.builder.setBasePath(context.ir.basePath); @@ -227,7 +227,11 @@ export function buildFernDefinition(context: OpenApiIrConverterContext): FernDef context.builder.optimizeServiceAuth(); - return context.builder.build(); + const definition = context.builder.build(); + if (oauthScopeType != null) { + addOauthScopeType(definition, oauthScopeType); + } + return definition; } function getSchemaIdsToExclude({ diff --git a/packages/cli/cli/changes/unreleased/fix-openapi-oauth-scope-name-collision.yml b/packages/cli/cli/changes/unreleased/fix-openapi-oauth-scope-name-collision.yml new file mode 100644 index 000000000000..5d7ee9736e8f --- /dev/null +++ b/packages/cli/cli/changes/unreleased/fix-openapi-oauth-scope-name-collision.yml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Avoid collisions between emitted OpenAPI type names and the generated OAuth scope enum. + type: fix