From 9eb6eae590ab0352a8d77660a100d41addd24072 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 9 May 2024 10:52:09 -0400 Subject: [PATCH 1/6] (improvement, yaml): Add and update default OAuth YAML configuration --- .pnp.cjs | 1 + packages/cli/configuration/src/DocsLinks.ts | 7 + packages/cli/configuration/src/index.ts | 1 + .../src/converters/convertOAuthUtils.ts | 173 ++++++++++---- packages/cli/yaml/validator/package.json | 3 +- .../invalid/{ => missing}/definition/api.yml | 14 +- .../invalid/{ => missing}/definition/auth.yml | 2 +- .../invalid/property-path/definition/api.yml | 14 ++ .../invalid/property-path/definition/auth.yml | 29 +++ .../fixtures/invalid/types/definition/api.yml | 13 ++ .../invalid/types/definition/auth.yml | 24 ++ .../fixtures/valid/alias/definition/api.yml | 11 + .../fixtures/valid/alias/definition/auth.yml | 26 +++ .../fixtures/valid/default/definition/api.yml | 11 + .../valid/default/definition/auth.yml | 22 ++ .../valid/query-parameters/definition/api.yml | 11 + .../query-parameters/definition/auth.yml | 20 ++ .../valid/{ => simple}/definition/api.yml | 2 +- .../valid/{ => simple}/definition/auth.yml | 4 +- .../valid-oauth/__test__/valid-oauth.test.ts | 126 +++++++++- .../src/rules/valid-oauth/valid-oauth.ts | 26 ++- .../validateRefreshTokenEndpoint.ts | 61 +++-- .../valid-oauth/validateTokenEndpoint.ts | 116 +++++++++- .../src/rules/valid-oauth/validateUtils.ts | 215 ++++++++++++++---- .../validateCursorPagination.ts | 2 +- .../validateOffsetPagination.ts | 2 +- .../rules/valid-pagination/validateUtils.ts | 10 +- .../src/utils/propertyValidatorUtils.ts | 67 +++++- .../OAuthAccessTokenPropertiesSchema.ts | 9 - ...OAuthAccessTokenRequestPropertiesSchema.ts | 9 + ...AuthAccessTokenResponsePropertiesSchema.ts | 9 + .../schemas/OAuthGetTokenEndpointSchema.ts | 6 +- .../OAuthRefreshTokenEndpointSchema.ts | 9 +- .../OAuthRefreshTokenPropertiesSchema.ts | 7 - ...AuthRefreshTokenRequestPropertiesSchema.ts | 7 + .../cli/yaml/yaml-schema/src/schemas/index.ts | 3 + .../definition/api.yml | 11 + .../definition/auth.yml | 23 ++ .../generators.yml | 0 .../definition/api.yml | 2 +- .../definition/auth.yml | 4 +- .../definition/api.yml | 2 +- .../definition/auth.yml | 2 +- yarn.lock | 1 + 44 files changed, 928 insertions(+), 189 deletions(-) create mode 100644 packages/cli/configuration/src/DocsLinks.ts rename packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/{ => missing}/definition/api.yml (71%) rename packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/{ => missing}/definition/auth.yml (98%) create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/api.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/auth.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/api.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/auth.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/api.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/auth.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/api.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/auth.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/api.yml create mode 100644 packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/auth.yml rename packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/{ => simple}/definition/api.yml (98%) rename packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/{ => simple}/definition/auth.yml (96%) delete mode 100644 packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenPropertiesSchema.ts create mode 100644 packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenRequestPropertiesSchema.ts create mode 100644 packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenResponsePropertiesSchema.ts delete mode 100644 packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenPropertiesSchema.ts create mode 100644 packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenRequestPropertiesSchema.ts create mode 100644 test-definitions/fern/apis/oauth-client-credentials-default/definition/api.yml create mode 100644 test-definitions/fern/apis/oauth-client-credentials-default/definition/auth.yml rename {packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid => test-definitions/fern/apis/oauth-client-credentials-default}/generators.yml (100%) diff --git a/.pnp.cjs b/.pnp.cjs index a3de950a302..107f403e08d 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -7618,6 +7618,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["organize-imports-cli", "npm:0.10.0"],\ ["prettier", "npm:2.7.1"],\ ["strip-ansi", "npm:7.1.0"],\ + ["terminal-link", "npm:3.0.0"],\ ["typescript", "patch:typescript@npm%3A4.6.4#~builtin::version=4.6.4&hash=5d3a66"]\ ],\ "linkType": "SOFT"\ diff --git a/packages/cli/configuration/src/DocsLinks.ts b/packages/cli/configuration/src/DocsLinks.ts new file mode 100644 index 00000000000..f3316970d35 --- /dev/null +++ b/packages/cli/configuration/src/DocsLinks.ts @@ -0,0 +1,7 @@ +export interface DocsLinks { + oauth: string; +} + +export const DocsLinks: DocsLinks = { + oauth: "https://buildwithfern.com/learn/api-definition/fern/api-yml-reference#authentication" +}; diff --git a/packages/cli/configuration/src/index.ts b/packages/cli/configuration/src/index.ts index 92bba3daa7c..63f59343d49 100644 --- a/packages/cli/configuration/src/index.ts +++ b/packages/cli/configuration/src/index.ts @@ -4,6 +4,7 @@ export * from "./commons/WithoutQuestionMarks"; export * from "./constants"; export * as dependenciesYml from "./dependencies-yml"; export * as docsYml from "./docs-yml"; +export { DocsLinks } from "./DocsLinks"; export * as fernConfigJson from "./fern-config-json"; export * as generatorsYml from "./generators-yml"; export { GeneratorName } from "./generators-yml/GeneratorName"; diff --git a/packages/cli/generation/ir-generator/src/converters/convertOAuthUtils.ts b/packages/cli/generation/ir-generator/src/converters/convertOAuthUtils.ts index db14f9fb010..6d9305f5748 100644 --- a/packages/cli/generation/ir-generator/src/converters/convertOAuthUtils.ts +++ b/packages/cli/generation/ir-generator/src/converters/convertOAuthUtils.ts @@ -1,6 +1,34 @@ import { RawSchemas } from "@fern-api/yaml-schema"; import { getRequestPropertyComponents, getResponsePropertyComponents } from "./services/convertProperty"; +const DEFAULT_TOKEN_ENDPOINT: Omit = { + requestProperties: { + type: "access_token", + client_id: ["client_id"], + client_secret: ["client_secret"], + scopes: undefined + }, + responseProperties: { + type: "access_token", + access_token: ["access_token"], + expires_in: undefined, + refresh_token: undefined + } +}; + +const DEFAULT_REFRESH_TOKEN_ENDPOINT: Omit = { + requestProperties: { + type: "refresh_token", + refresh_token: ["refresh_token"] + }, + responseProperties: { + type: "access_token", + access_token: ["access_token"], + refresh_token: undefined, + expires_in: undefined + } +}; + export interface TokenEndpoint { endpoint: string; requestProperties: OAuthAccessTokenRequestPropertyComponents; @@ -33,34 +61,14 @@ interface OAuthRefreshTokenRequestPropertyComponents { } export function getTokenEndpoint(oauthSchema: RawSchemas.OAuthSchemeSchema): TokenEndpoint { - // const maybeScopes = oauthSchema["get-token"]["request-properties"].scopes; - const maybeExpiresIn = oauthSchema["get-token"]["response-properties"]["expires-in"]; - const maybeRefreshToken = oauthSchema["get-token"]["response-properties"]["refresh-token"]; return { endpoint: oauthSchema["get-token"].endpoint, - // TODO: Update the YAML schema and make this configurable with the following: - // requestProperties: { - // type: "access_token", - // client_id: getRequestPropertyComponents(oauthSchema["get-token"]["request-properties"]["client-id"]), - // client_secret: getRequestPropertyComponents( - // oauthSchema["get-token"]["request-properties"]["client-secret"] - // ), - // scopes: maybeScopes != null ? getRequestPropertyComponents(maybeScopes) : undefined - // }, - requestProperties: { - type: "access_token", - client_id: ["client_id"], - client_secret: ["client_secret"], - scopes: undefined - }, - responseProperties: { - type: "access_token", - access_token: getResponsePropertyComponents( - oauthSchema["get-token"]["response-properties"]["access-token"] - ), - expires_in: maybeExpiresIn != null ? getResponsePropertyComponents(maybeExpiresIn) : undefined, - refresh_token: maybeRefreshToken != null ? getResponsePropertyComponents(maybeRefreshToken) : undefined - } + requestProperties: getTokenEndpointRequestProperties({ + requestProperties: oauthSchema["get-token"]?.["request-properties"] + }), + responseProperties: getTokenEndpointResponseProperties({ + responseProperties: oauthSchema["get-token"]?.["response-properties"] + }) }; } @@ -68,23 +76,104 @@ export function getRefreshTokenEndpoint(oauthSchema: RawSchemas.OAuthSchemeSchem if (oauthSchema["refresh-token"] == null) { return undefined; } - const maybeExpiresIn = oauthSchema["get-token"]["response-properties"]["expires-in"]; - const maybeRefreshToken = oauthSchema["get-token"]["response-properties"]["refresh-token"]; return { endpoint: oauthSchema["refresh-token"].endpoint, - requestProperties: { - type: "refresh_token", - refresh_token: getRequestPropertyComponents( - oauthSchema["refresh-token"]["request-properties"]["refresh-token"] - ) - }, - responseProperties: { - type: "access_token", - access_token: getResponsePropertyComponents( - oauthSchema["get-token"]["response-properties"]["access-token"] - ), - expires_in: maybeExpiresIn != null ? getResponsePropertyComponents(maybeExpiresIn) : undefined, - refresh_token: maybeRefreshToken != null ? getResponsePropertyComponents(maybeRefreshToken) : undefined - } + requestProperties: getRefreshTokenEndpointRequestProperties({ + requestProperties: oauthSchema["refresh-token"]?.["request-properties"] + }), + responseProperties: getRefreshTokenEndpointResponseProperties({ + responseProperties: oauthSchema["refresh-token"]?.["response-properties"] + }) + }; +} + +function getTokenEndpointRequestProperties({ + requestProperties +}: { + requestProperties: RawSchemas.OAuthAccessTokenRequestPropertiesSchema | undefined; +}): OAuthAccessTokenRequestPropertyComponents { + if (requestProperties == null) { + return DEFAULT_TOKEN_ENDPOINT.requestProperties; + } + const maybeClientId = requestProperties["client-id"]; + const maybeClientSecret = requestProperties["client-secret"]; + const maybeScopes = requestProperties.scopes; + return { + type: "access_token", + client_id: + maybeClientId != null + ? getRequestPropertyComponents(maybeClientId) + : DEFAULT_TOKEN_ENDPOINT.requestProperties.client_id, + client_secret: + maybeClientSecret != null + ? getRequestPropertyComponents(maybeClientSecret) + : DEFAULT_TOKEN_ENDPOINT.requestProperties.client_secret, + scopes: + maybeScopes != null + ? getRequestPropertyComponents(maybeScopes) + : DEFAULT_TOKEN_ENDPOINT.requestProperties.scopes + }; +} + +function getTokenEndpointResponseProperties({ + responseProperties +}: { + responseProperties: RawSchemas.OAuthAccessTokenResponsePropertiesSchema | undefined; +}): OAuthAccessTokenResponsePropertyComponents { + return getTokenEndpointResponsePropertiesWithDefault({ + responseProperties, + defaultValue: DEFAULT_TOKEN_ENDPOINT.responseProperties + }); +} + +function getRefreshTokenEndpointRequestProperties({ + requestProperties +}: { + requestProperties: RawSchemas.OAuthRefreshTokenRequestPropertiesSchema | undefined; +}): OAuthRefreshTokenRequestPropertyComponents { + if (requestProperties == null) { + return DEFAULT_REFRESH_TOKEN_ENDPOINT.requestProperties; + } + const maybeRefreshToken = requestProperties["refresh-token"]; + return { + type: "refresh_token", + refresh_token: + maybeRefreshToken != null + ? getRequestPropertyComponents(maybeRefreshToken) + : DEFAULT_REFRESH_TOKEN_ENDPOINT.requestProperties.refresh_token + }; +} + +function getRefreshTokenEndpointResponseProperties({ + responseProperties +}: { + responseProperties: RawSchemas.OAuthAccessTokenResponsePropertiesSchema | undefined; +}): OAuthAccessTokenResponsePropertyComponents { + return getTokenEndpointResponsePropertiesWithDefault({ + responseProperties, + defaultValue: DEFAULT_REFRESH_TOKEN_ENDPOINT.responseProperties + }); +} + +function getTokenEndpointResponsePropertiesWithDefault({ + responseProperties, + defaultValue +}: { + responseProperties: RawSchemas.OAuthAccessTokenResponsePropertiesSchema | undefined; + defaultValue: OAuthAccessTokenResponsePropertyComponents; +}): OAuthAccessTokenResponsePropertyComponents { + if (responseProperties == null) { + return defaultValue; + } + const maybeAccessToken = responseProperties["access-token"]; + const maybeExpiresIn = responseProperties["expires-in"]; + const maybeRefreshToken = responseProperties["refresh-token"]; + return { + type: "access_token", + access_token: + maybeAccessToken != null ? getResponsePropertyComponents(maybeAccessToken) : defaultValue.access_token, + expires_in: maybeExpiresIn != null ? getResponsePropertyComponents(maybeExpiresIn) : defaultValue.expires_in, + refresh_token: + maybeRefreshToken != null ? getResponsePropertyComponents(maybeRefreshToken) : defaultValue.refresh_token }; } diff --git a/packages/cli/yaml/validator/package.json b/packages/cli/yaml/validator/package.json index bcccc099564..285bd3cbaac 100644 --- a/packages/cli/yaml/validator/package.json +++ b/packages/cli/yaml/validator/package.json @@ -37,7 +37,8 @@ "@fern-api/yaml-schema": "workspace:*", "chalk": "^5.0.1", "lodash-es": "^4.17.21", - "strip-ansi": "^7.1.0" + "strip-ansi": "^7.1.0", + "terminal-link": "^3.0.0" }, "devDependencies": { "@types/jest": "^29.0.3", diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/api.yml similarity index 71% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/api.yml rename to packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/api.yml index 582ecd8f59a..d13294f290a 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/api.yml +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/api.yml @@ -1,5 +1,5 @@ -name: invalid -imports: +name: missing +imports: auth: auth.yml auth: OAuthScheme @@ -7,12 +7,12 @@ auth-schemes: OAuthScheme: scheme: oauth type: client-credentials - get-token: + get-token: endpoint: auth.getTokenWithClientCredentials - response-properties: - access-token: $response.missing.access_token - expires-in: $response.missing.expires_in - refresh-token: + response-properties: + access-token: $response.accessToken + expires-in: $response.expiresIn + refresh-token: endpoint: auth.refreshToken request-properties: refresh-token: $request.refreshTokenDoesNotExist diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/auth.yml similarity index 98% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/auth.yml rename to packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/auth.yml index e52e3cee177..e7887dddb67 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/definition/auth.yml +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/missing/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/api.yml new file mode 100644 index 00000000000..d18ad5b19c3 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/api.yml @@ -0,0 +1,14 @@ +name: invalid +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken + request-properties: + client-id: $request.credentials.client_id + client-secret: $request.credentials.client_secret \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/auth.yml new file mode 100644 index 00000000000..ce6074f746f --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/property-path/definition/auth.yml @@ -0,0 +1,29 @@ +types: + TokenCredentials: + docs: | + The credentials required to retrieve an access token. + properties: + client_id: string + client_secret: string + + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + refresh_token: optional + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + credentials: TokenCredentials + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/api.yml new file mode 100644 index 00000000000..a359229fc56 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/api.yml @@ -0,0 +1,13 @@ +name: invalid +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken + request-properties: + scopes: $request.scopes \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/auth.yml new file mode 100644 index 00000000000..de1b6e4525d --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/invalid/types/definition/auth.yml @@ -0,0 +1,24 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + refresh_token: optional + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: uuid + client_secret: uuid + scopes: integer + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/api.yml new file mode 100644 index 00000000000..7dd0fe0c045 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/api.yml @@ -0,0 +1,11 @@ +name: alias +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/auth.yml new file mode 100644 index 00000000000..d8d54d48535 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/alias/definition/auth.yml @@ -0,0 +1,26 @@ +types: + ClientID: string + ClientSecret: string + AccessToken: string + + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: AccessToken + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: ClientID + client_secret: ClientSecret + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/api.yml new file mode 100644 index 00000000000..a74aef6a412 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/api.yml @@ -0,0 +1,11 @@ +name: valid-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/auth.yml new file mode 100644 index 00000000000..f71f44ef31b --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/default/definition/auth.yml @@ -0,0 +1,22 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/api.yml new file mode 100644 index 00000000000..a74aef6a412 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/api.yml @@ -0,0 +1,11 @@ +name: valid-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/auth.yml new file mode 100644 index 00000000000..34ebf18d526 --- /dev/null +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/query-parameters/definition/auth.yml @@ -0,0 +1,20 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: GET + request: + name: GetTokenRequest + query-parameters: + client_id: string + client_secret: string + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/api.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/api.yml similarity index 98% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/api.yml rename to packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/api.yml index ed7324af308..83a416712b6 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/api.yml +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/api.yml @@ -1,5 +1,5 @@ name: valid -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/auth.yml b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/auth.yml similarity index 96% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/auth.yml rename to packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/auth.yml index e52e3cee177..b0dc81c642a 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/definition/auth.yml +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/simple/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: @@ -28,7 +28,7 @@ service: refreshToken: path: /token method: POST - request: + request: name: RefreshTokenRequest body: properties: diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts index 386a8530d0e..778672744a2 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts @@ -4,66 +4,136 @@ import { ValidationViolation } from "../../../ValidationViolation"; import { ValidOauthRule } from "../valid-oauth"; describe("valid-oauth", () => { - it("valid", async () => { + it("valid-default", async () => { const violations = await getViolationsForRule({ rule: ValidOauthRule, absolutePathToWorkspace: join( AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures"), - RelativeFilePath.of("valid") + RelativeFilePath.of("valid"), + RelativeFilePath.of("default") ) }); expect(violations).toEqual([]); }); - it("invalid", async () => { + it("valid-simple", async () => { const violations = await getViolationsForRule({ rule: ValidOauthRule, absolutePathToWorkspace: join( AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures"), - RelativeFilePath.of("invalid") + RelativeFilePath.of("valid"), + RelativeFilePath.of("simple") + ) + }); + expect(violations).toEqual([]); + }); + + it("valid-query-parameters", async () => { + const violations = await getViolationsForRule({ + rule: ValidOauthRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("valid"), + RelativeFilePath.of("query-parameters") + ) + }); + expect(violations).toEqual([]); + }); + + it("valid-alias", async () => { + const violations = await getViolationsForRule({ + rule: ValidOauthRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("valid"), + RelativeFilePath.of("alias") + ) + }); + expect(violations).toEqual([]); + }); + + it("invalid-property-path", async () => { + const violations = await getViolationsForRule({ + rule: ValidOauthRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("invalid"), + RelativeFilePath.of("property-path") ) }); const expectedViolations: ValidationViolation[] = [ { message: - "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'access-token' $response.missing.access_token, which is not a valid 'access-token' type.", + "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_id'; expected '$request.client-id' instead. For details, see the docs.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + }, + { + message: + "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_secret'; expected '$request.client-secret' instead. For details, see the docs.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + } + ]; + expect(violations).toEqual(expectedViolations); + }); + + it("invalid-missing", async () => { + const violations = await getViolationsForRule({ + rule: ValidOauthRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("invalid"), + RelativeFilePath.of("missing") + ) + }); + const expectedViolations: ValidationViolation[] = [ + { + message: + "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'access-token' $response.accessToken, which is not a valid 'access-token' type. For details, see the docs.", nodePath: ["service", "endpoints", "getTokenWithClientCredentials"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'expires-in' $response.missing.expires_in, which is not a valid 'expires-in' type.", + "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'expires-in' $response.expiresIn, which is not a valid 'expires-in' type. For details, see the docs.", nodePath: ["service", "endpoints", "getTokenWithClientCredentials"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $request.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type.", + "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $request.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type. For details, see the docs.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'access-token' $response.accessTokenDoesNotExist, which is not a valid 'access-token' type.", + "OAuth configuration for endpoint refreshToken specifies 'access-token' $response.accessTokenDoesNotExist, which is not a valid 'access-token' type. For details, see the docs.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'expires-in' $response.expiresInDoesNotExist, which is not a valid 'expires-in' type.", + "OAuth configuration for endpoint refreshToken specifies 'expires-in' $response.expiresInDoesNotExist, which is not a valid 'expires-in' type. For details, see the docs.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $response.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type.", + "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $response.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type. For details, see the docs.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" @@ -71,4 +141,40 @@ describe("valid-oauth", () => { ]; expect(violations).toEqual(expectedViolations); }); + + it("invalid-types", async () => { + const violations = await getViolationsForRule({ + rule: ValidOauthRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("invalid"), + RelativeFilePath.of("types") + ) + }); + const expectedViolations: ValidationViolation[] = [ + { + message: + "OAuth configuration for endpoint getToken is missing a valid client-id, such as '$request.client_id'. For details, see the docs.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + }, + { + message: + "OAuth configuration for endpoint getToken is missing a valid client-secret, such as '$request.client_secret'. For details, see the docs.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + }, + { + message: + "OAuth configuration for endpoint getToken specifies 'scopes' $request.scopes, which is not a valid 'scopes' type. For details, see the docs.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + } + ]; + expect(violations).toEqual(expectedViolations); + }); }); diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/valid-oauth.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/valid-oauth.ts index 98b255084c5..3ebfef3aad0 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/valid-oauth.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/valid-oauth.ts @@ -1,3 +1,4 @@ +import { DocsLinks } from "@fern-api/configuration"; import { assertNever } from "@fern-api/core-utils"; import { constructFernFileContext, @@ -7,10 +8,15 @@ import { } from "@fern-api/ir-generator"; import { FernWorkspace } from "@fern-api/workspace-loader"; import { RawSchemas } from "@fern-api/yaml-schema"; +import terminalLink from "terminal-link"; import { Rule } from "../../Rule"; import { CASINGS_GENERATOR } from "../../utils/casingsGenerator"; import { validateClientCredentials } from "./validateClientCredentials"; +const DOCS_LINK_MESSAGE = `For details, see the ${terminalLink("docs", DocsLinks.oauth, { + fallback: (text, url) => `${text}: ${url}` +})}.`; + export const ValidOauthRule: Rule = { name: "valid-oauth", create: ({ workspace }) => { @@ -31,7 +37,7 @@ export const ValidOauthRule: Rule = { return [ { severity: "error", - message: `File declares oauth scheme '${oauthScheme.name}', but no imports are declared to reference the required token endpoint(s).` + message: `File declares oauth scheme '${oauthScheme.name}', but no imports are declared to reference the required token endpoint(s). ${DOCS_LINK_MESSAGE}` } ]; } @@ -55,7 +61,7 @@ export const ValidOauthRule: Rule = { return [ { severity: "error", - message: `File declares oauth scheme '${oauthScheme.name}', but the OAuth 'get-token' endpoint could not be resolved.` + message: `File declares oauth scheme '${oauthScheme.name}', but the OAuth 'get-token' endpoint could not be resolved. ${DOCS_LINK_MESSAGE}` } ]; } @@ -77,7 +83,7 @@ export const ValidOauthRule: Rule = { return [ { severity: "error", - message: `File declares oauth scheme '${oauthScheme.name}', but the OAuth 'refresh-token' endpoint could not be resolved.` + message: `File declares oauth scheme '${oauthScheme.name}', but the OAuth 'refresh-token' endpoint could not be resolved. ${DOCS_LINK_MESSAGE}` } ]; } @@ -85,8 +91,6 @@ export const ValidOauthRule: Rule = { }; } - // TODO: Add the default request-properties and response-properties if not set. - return { definitionFile: { httpEndpoint: ({ endpointId, endpoint }, { relativeFilepath, contents: definitionFile }) => { @@ -105,8 +109,8 @@ export const ValidOauthRule: Rule = { }); switch (oauthSchema.type) { - case "client-credentials": - return validateClientCredentials({ + case "client-credentials": { + const violations = validateClientCredentials({ endpointId, endpoint, typeResolver, @@ -115,6 +119,14 @@ export const ValidOauthRule: Rule = { resolvedRefreshEndpoint, clientCredentials: oauthSchema }); + if (violations.length > 0) { + return violations.map((violation) => ({ + severity: violation.severity, + message: violation.message + ` ${DOCS_LINK_MESSAGE}` + })); + } + return []; + } default: assertNever(oauthSchema.type); } diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/validateRefreshTokenEndpoint.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/validateRefreshTokenEndpoint.ts index 398aca0e482..8f81502f0d4 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/validateRefreshTokenEndpoint.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/validateRefreshTokenEndpoint.ts @@ -4,6 +4,8 @@ import chalk from "chalk"; import { RuleViolation } from "../../Rule"; import { maybeFileFromResolvedType, resolveResponseType } from "../../utils/propertyValidatorUtils"; import { + DEFAULT_ACCESS_TOKEN, + DEFAULT_REFRESH_TOKEN, validateAccessTokenResponseProperty, validateExpiresInResponseProperty, validateRefreshTokenRequestProperty, @@ -25,15 +27,34 @@ export function validateRefreshTokenEndpoint({ }): RuleViolation[] { const violations: RuleViolation[] = []; - violations.push( - ...validateRefreshTokenRequestProperty({ + const maybeRefreshToken = refreshEndpoint["request-properties"]?.["refresh-token"]; + if (maybeRefreshToken != null) { + violations.push( + ...validateRefreshTokenRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + refreshTokenProperty: maybeRefreshToken + }) + ); + } else { + const refreshTokenViolations = validateRefreshTokenRequestProperty({ endpointId, endpoint, typeResolver, file, - refreshTokenProperty: refreshEndpoint["request-properties"]["refresh-token"] - }) - ); + refreshTokenProperty: DEFAULT_REFRESH_TOKEN + }); + if (refreshTokenViolations.length > 0) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} is missing a valid refresh-token, such as '${DEFAULT_REFRESH_TOKEN}'.` + }); + } + } const resolvedResponseType = resolveResponseType({ endpoint, typeResolver, file }); if (resolvedResponseType == null) { @@ -44,20 +65,36 @@ export function validateRefreshTokenEndpoint({ return violations; } - const accessTokenProperty = refreshEndpoint["response-properties"]["access-token"]; - if (accessTokenProperty != null) { + const maybeAccessToken = refreshEndpoint["response-properties"]?.["access-token"]; + if (maybeAccessToken != null) { violations.push( ...validateAccessTokenResponseProperty({ endpointId, typeResolver, - file: maybeFileFromResolvedType(resolvedResponseType) ?? file, + file, resolvedResponseType, - accessTokenProperty + accessTokenProperty: maybeAccessToken }) ); + } else { + const accessTokenViolations = validateAccessTokenResponseProperty({ + endpointId, + typeResolver, + file, + resolvedResponseType, + accessTokenProperty: DEFAULT_ACCESS_TOKEN + }); + if (accessTokenViolations.length > 0) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} is missing a valid access-token, such as '${DEFAULT_ACCESS_TOKEN}'.` + }); + } } - const expiresInProperty = refreshEndpoint["response-properties"]["expires-in"]; + const expiresInProperty = refreshEndpoint?.["response-properties"]?.["expires-in"]; if (expiresInProperty != null) { violations.push( ...validateExpiresInResponseProperty({ @@ -70,7 +107,7 @@ export function validateRefreshTokenEndpoint({ ); } - const refreshTokenProperty = refreshEndpoint["response-properties"]["refresh-token"]; + const refreshTokenProperty = refreshEndpoint?.["response-properties"]?.["refresh-token"]; if (refreshTokenProperty != null) { violations.push( ...validateRefreshTokenResponseProperty({ @@ -83,7 +120,5 @@ export function validateRefreshTokenEndpoint({ ); } - // TODO: Validate the request has 'grant_type: literal<"refresh_token">'. - return violations; } diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/validateTokenEndpoint.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/validateTokenEndpoint.ts index ddd49c1d836..6d98bdc08a9 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/validateTokenEndpoint.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/validateTokenEndpoint.ts @@ -4,9 +4,15 @@ import chalk from "chalk"; import { RuleViolation } from "../../Rule"; import { maybeFileFromResolvedType, resolveResponseType } from "../../utils/propertyValidatorUtils"; import { + DEFAULT_ACCESS_TOKEN, + DEFAULT_CLIENT_ID, + DEFAULT_CLIENT_SECRET, validateAccessTokenResponseProperty, + validateClientIdRequestProperty, + validateClientSecretRequestProperty, validateExpiresInResponseProperty, - validateRefreshTokenResponseProperty + validateRefreshTokenResponseProperty, + validateScopesRequestProperty } from "./validateUtils"; export function validateTokenEndpoint({ @@ -24,6 +30,77 @@ export function validateTokenEndpoint({ }): RuleViolation[] { const violations: RuleViolation[] = []; + const maybeClientId = tokenEndpoint["request-properties"]?.["client-id"]; + if (maybeClientId != null) { + violations.push( + ...validateClientIdRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + clientIdProperty: maybeClientId + }) + ); + } else { + const clientIdViolations = validateClientIdRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + clientIdProperty: DEFAULT_CLIENT_ID + }); + if (clientIdViolations.length > 0) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} is missing a valid client-id, such as '${DEFAULT_CLIENT_ID}'.` + }); + } + } + + const maybeClientSecret = tokenEndpoint["request-properties"]?.["client-secret"]; + if (maybeClientSecret != null) { + violations.push( + ...validateClientSecretRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + clientSecretProperty: maybeClientSecret + }) + ); + } else { + const clientSecretViolations = validateClientSecretRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + clientSecretProperty: DEFAULT_CLIENT_SECRET + }); + if (clientSecretViolations.length > 0) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} is missing a valid client-secret, such as '${DEFAULT_CLIENT_SECRET}'.` + }); + } + } + + const scopesProperty = tokenEndpoint?.["request-properties"]?.scopes; + if (scopesProperty != null) { + violations.push( + ...validateScopesRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + scopesProperty + }) + ); + } + const resolvedResponseType = resolveResponseType({ endpoint, typeResolver, file }); if (resolvedResponseType == null) { violations.push({ @@ -33,17 +110,36 @@ export function validateTokenEndpoint({ return violations; } - violations.push( - ...validateAccessTokenResponseProperty({ + const maybeAccessToken = tokenEndpoint["response-properties"]?.["access-token"]; + if (maybeAccessToken != null) { + violations.push( + ...validateAccessTokenResponseProperty({ + endpointId, + typeResolver, + file, + resolvedResponseType, + accessTokenProperty: maybeAccessToken + }) + ); + } else { + const accessTokenViolations = validateAccessTokenResponseProperty({ endpointId, typeResolver, - file: maybeFileFromResolvedType(resolvedResponseType) ?? file, + file, resolvedResponseType, - accessTokenProperty: tokenEndpoint["response-properties"]["access-token"] - }) - ); + accessTokenProperty: DEFAULT_ACCESS_TOKEN + }); + if (accessTokenViolations.length > 0) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} is missing a valid access-token, such as '${DEFAULT_ACCESS_TOKEN}'.` + }); + } + } - const expiresInProperty = tokenEndpoint["response-properties"]["expires-in"]; + const expiresInProperty = tokenEndpoint?.["response-properties"]?.["expires-in"]; if (expiresInProperty != null) { violations.push( ...validateExpiresInResponseProperty({ @@ -56,7 +152,7 @@ export function validateTokenEndpoint({ ); } - const refreshTokenProperty = tokenEndpoint["response-properties"]["refresh-token"]; + const refreshTokenProperty = tokenEndpoint?.["response-properties"]?.["refresh-token"]; if (refreshTokenProperty != null) { violations.push( ...validateRefreshTokenResponseProperty({ @@ -69,7 +165,5 @@ export function validateTokenEndpoint({ ); } - // TODO: Validate the request has 'grant_type: literal<"client_credentials">'. - return violations; } diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/validateUtils.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/validateUtils.ts index 37a2fe7d6f7..db3095fdbb0 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/validateUtils.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/validateUtils.ts @@ -6,55 +6,121 @@ import { getRequestPropertyComponents, getResponsePropertyComponents, maybePrimitiveType, - PropertyValidator, + RequestPropertyValidator, requestTypeHasProperty, - resolvedTypeHasProperty + REQUEST_PREFIX, + resolvedTypeHasProperty, + ResponsePropertyValidator, + RESPONSE_PREFIX } from "../../utils/propertyValidatorUtils"; -export function validateRefreshTokenRequestProperty({ +export const DEFAULT_CLIENT_ID = `${REQUEST_PREFIX}client_id`; +export const DEFAULT_CLIENT_SECRET = `${REQUEST_PREFIX}client_secret`; +export const DEFAULT_ACCESS_TOKEN = `${RESPONSE_PREFIX}access_token`; +export const DEFAULT_REFRESH_TOKEN = `${REQUEST_PREFIX}refresh_token`; + +export function validateClientIdRequestProperty({ endpointId, endpoint, typeResolver, file, - refreshTokenProperty + clientIdProperty }: { endpointId: string; endpoint: RawSchemas.HttpEndpointSchema; typeResolver: TypeResolver; file: FernFileContext; - refreshTokenProperty: string; + clientIdProperty: string; }): RuleViolation[] { - const violations: RuleViolation[] = []; + return validateRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + requestProperty: clientIdProperty, + propertyValidator: { + propertyID: "client-id", + validate: isStringType + } + }); +} - const refreshTokenPropertyComponents = getRequestPropertyComponents(refreshTokenProperty); - if (refreshTokenPropertyComponents == null) { - violations.push({ - severity: "error", - message: `OAuth configuration for endpoint ${chalk.bold( - endpointId - )} must define a dot-delimited 'refresh-token' property starting with $request (e.g. $request.refresh_token).` - }); - return violations; - } +export function validateClientSecretRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + clientSecretProperty +}: { + endpointId: string; + endpoint: RawSchemas.HttpEndpointSchema; + typeResolver: TypeResolver; + file: FernFileContext; + clientSecretProperty: string; +}): RuleViolation[] { + return validateRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + requestProperty: clientSecretProperty, + propertyValidator: { + propertyID: "client-secret", + validate: isStringType + } + }); +} - if ( - !requestTypeHasProperty({ - typeResolver, - file, - endpoint, - propertyComponents: refreshTokenPropertyComponents, - validate: isValidTokenType - }) - ) { - violations.push({ - severity: "error", - message: `OAuth configuration for endpoint ${chalk.bold( - endpointId - )} specifies 'refresh-token' ${refreshTokenProperty}, which is not a valid 'refresh-token' type.` - }); - } +export function validateScopesRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + scopesProperty +}: { + endpointId: string; + endpoint: RawSchemas.HttpEndpointSchema; + typeResolver: TypeResolver; + file: FernFileContext; + scopesProperty: string; +}): RuleViolation[] { + return validateRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + requestProperty: scopesProperty, + propertyValidator: { + propertyID: "scopes", + validate: isStringType + } + }); +} - return violations; +export function validateRefreshTokenRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + refreshTokenProperty +}: { + endpointId: string; + endpoint: RawSchemas.HttpEndpointSchema; + typeResolver: TypeResolver; + file: FernFileContext; + refreshTokenProperty: string; +}): RuleViolation[] { + return validateRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + requestProperty: refreshTokenProperty, + propertyValidator: { + propertyID: "refresh-token", + validate: isStringType + } + }); } export function validateAccessTokenResponseProperty({ @@ -151,18 +217,10 @@ function isValidExpiresInProperty({ file, resolvedType, propertyComponents, - validate: isValidExpiryType + validate: isIntegerType }); } -function isValidExpiryType(resolvedType: ResolvedType | undefined): boolean { - const primitiveType = maybePrimitiveType(resolvedType); - if (primitiveType == null) { - return false; - } - return primitiveType === "INTEGER"; -} - function isValidTokenProperty({ typeResolver, file, @@ -179,16 +237,67 @@ function isValidTokenProperty({ file, resolvedType, propertyComponents, - validate: isValidTokenType + validate: isStringType }); } -function isValidTokenType(resolvedType: ResolvedType | undefined): boolean { - const primitiveType = maybePrimitiveType(resolvedType); - if (primitiveType == null) { - return false; +function validateRequestProperty({ + endpointId, + endpoint, + typeResolver, + file, + requestProperty, + propertyValidator +}: { + endpointId: string; + endpoint: RawSchemas.HttpEndpointSchema; + typeResolver: TypeResolver; + file: FernFileContext; + requestProperty: string; + propertyValidator: RequestPropertyValidator; +}): RuleViolation[] { + const violations: RuleViolation[] = []; + + const requestPropertyComponents = getRequestPropertyComponents(requestProperty); + if (requestPropertyComponents == null) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold(endpointId)} must define a dot-delimited '${ + propertyValidator.propertyID + }' property starting with $request (e.g. $request.${propertyValidator.propertyID}).` + }); + return violations; + } + if (requestPropertyComponents.length > 1) { + // For now, we prevent request properties from being nested further than the top-level. + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold( + endpointId + )} cannot reference nested $request properties like '${requestProperty}'; expected '$request.${ + propertyValidator.propertyID + }' instead.` + }); + return violations; + } + if ( + !requestTypeHasProperty({ + typeResolver, + file, + endpoint, + propertyComponents: requestPropertyComponents, + validate: propertyValidator.validate + }) + ) { + violations.push({ + severity: "error", + message: `OAuth configuration for endpoint ${chalk.bold(endpointId)} specifies '${ + propertyValidator.propertyID + }' ${requestProperty}, which is not a valid '${propertyValidator.propertyID}' type.` + }); } - return primitiveType === "STRING"; + + return violations; } function validateResponseProperty({ @@ -204,7 +313,7 @@ function validateResponseProperty({ file: FernFileContext; resolvedResponseType: ResolvedType; responseProperty: string; - propertyValidator: PropertyValidator; + propertyValidator: ResponsePropertyValidator; }): RuleViolation[] { const violations: RuleViolation[] = []; @@ -237,3 +346,11 @@ function validateResponseProperty({ return violations; } + +function isIntegerType({ resolvedType }: { resolvedType: ResolvedType | undefined }): boolean { + return maybePrimitiveType(resolvedType) === "INTEGER"; +} + +function isStringType({ resolvedType }: { resolvedType: ResolvedType | undefined }): boolean { + return maybePrimitiveType(resolvedType) === "STRING"; +} diff --git a/packages/cli/yaml/validator/src/rules/valid-pagination/validateCursorPagination.ts b/packages/cli/yaml/validator/src/rules/valid-pagination/validateCursorPagination.ts index 3398a812388..871170a0c83 100644 --- a/packages/cli/yaml/validator/src/rules/valid-pagination/validateCursorPagination.ts +++ b/packages/cli/yaml/validator/src/rules/valid-pagination/validateCursorPagination.ts @@ -139,7 +139,7 @@ function isValidCursorProperty({ }); } -function isValidCursorType(resolvedType: ResolvedType | undefined): boolean { +function isValidCursorType({ resolvedType }: { resolvedType: ResolvedType | undefined }): boolean { const primitiveType = maybePrimitiveType(resolvedType); if (primitiveType == null) { return false; diff --git a/packages/cli/yaml/validator/src/rules/valid-pagination/validateOffsetPagination.ts b/packages/cli/yaml/validator/src/rules/valid-pagination/validateOffsetPagination.ts index a5cdb669440..23fe7061c5d 100644 --- a/packages/cli/yaml/validator/src/rules/valid-pagination/validateOffsetPagination.ts +++ b/packages/cli/yaml/validator/src/rules/valid-pagination/validateOffsetPagination.ts @@ -103,7 +103,7 @@ function isValidOffsetProperty({ }); } -function isValidOffsetType(resolvedType: ResolvedType | undefined): boolean { +function isValidOffsetType({ resolvedType }: { resolvedType: ResolvedType | undefined }): boolean { const primitiveType = maybePrimitiveType(resolvedType); if (primitiveType == null) { return false; diff --git a/packages/cli/yaml/validator/src/rules/valid-pagination/validateUtils.ts b/packages/cli/yaml/validator/src/rules/valid-pagination/validateUtils.ts index 6df3e7d5e5c..d627f3c664d 100644 --- a/packages/cli/yaml/validator/src/rules/valid-pagination/validateUtils.ts +++ b/packages/cli/yaml/validator/src/rules/valid-pagination/validateUtils.ts @@ -6,8 +6,8 @@ import { getRequestPropertyComponents, getResponsePropertyComponents, maybeFileFromResolvedType, - PropertyValidator, - resolvedTypeHasProperty + resolvedTypeHasProperty, + ResponsePropertyValidator } from "../../utils/propertyValidatorUtils"; export function validateResultsProperty({ @@ -49,7 +49,7 @@ export function validateQueryParameterProperty({ typeResolver: TypeResolver; file: FernFileContext; queryParameterProperty: string; - propertyValidator: PropertyValidator; + propertyValidator: ResponsePropertyValidator; }): RuleViolation[] { const violations: RuleViolation[] = []; @@ -134,7 +134,7 @@ export function validateResponseProperty({ file: FernFileContext; resolvedResponseType: ResolvedType; responseProperty: string; - propertyValidator: PropertyValidator; + propertyValidator: ResponsePropertyValidator; }): RuleViolation[] { const violations: RuleViolation[] = []; @@ -188,6 +188,6 @@ function isValidResultsProperty({ }); } -function isValidResultsType(resolvedType: ResolvedType | undefined): boolean { +function isValidResultsType({ resolvedType }: { resolvedType: ResolvedType | undefined }): boolean { return true; } diff --git a/packages/cli/yaml/validator/src/utils/propertyValidatorUtils.ts b/packages/cli/yaml/validator/src/utils/propertyValidatorUtils.ts index 8c68b714259..2871d390e35 100644 --- a/packages/cli/yaml/validator/src/utils/propertyValidatorUtils.ts +++ b/packages/cli/yaml/validator/src/utils/propertyValidatorUtils.ts @@ -1,15 +1,22 @@ import { FernFileContext, ResolvedType, TypeResolver } from "@fern-api/ir-generator"; import { isInlineRequestBody, isRawObjectDefinition, RawSchemas } from "@fern-api/yaml-schema"; -const REQUEST_PREFIX = "$request."; -const RESPONSE_PREFIX = "$response."; +export const REQUEST_PREFIX = "$request."; +export const RESPONSE_PREFIX = "$response."; -export interface PropertyValidator { +export interface RequestPropertyValidator { propertyID: string; - validate: PropertyValidatorFunc; + validate: RequestPropertyValidatorFunc; } -export type PropertyValidatorFunc = ({ +export type RequestPropertyValidatorFunc = ({ resolvedType }: { resolvedType: ResolvedType | undefined }) => boolean; + +export interface ResponsePropertyValidator { + propertyID: string; + validate: ResponsePropertyValidatorFunc; +} + +export type ResponsePropertyValidatorFunc = ({ typeResolver, file, resolvedType, @@ -32,7 +39,7 @@ export function requestTypeHasProperty({ file: FernFileContext; endpoint: RawSchemas.HttpEndpointSchema; propertyComponents: string[]; - validate: (resolvedType: ResolvedType | undefined) => boolean; + validate: RequestPropertyValidatorFunc; }): boolean { if (endpoint.request == null) { return false; @@ -69,8 +76,19 @@ function inlinedRequestTypeHasProperty({ file: FernFileContext; requestType: RawSchemas.HttpRequestSchema; propertyComponents: string[]; - validate: (resolvedType: ResolvedType | undefined) => boolean; + validate: RequestPropertyValidatorFunc; }): boolean { + if ( + isQueryParameterProperty({ + typeResolver, + file, + requestType, + propertyComponents, + validate + }) + ) { + return true; + } if (requestType.body == null) { return false; } @@ -107,6 +125,35 @@ function inlinedRequestTypeHasProperty({ }); } +export function isQueryParameterProperty({ + typeResolver, + file, + requestType, + propertyComponents, + validate +}: { + typeResolver: TypeResolver; + file: FernFileContext; + requestType: RawSchemas.HttpRequestSchema; + propertyComponents: string[]; + validate: RequestPropertyValidatorFunc; +}): boolean { + if (propertyComponents.length !== 1 || typeof requestType === "string" || requestType["query-parameters"] == null) { + return false; + } + const queryParameter = requestType["query-parameters"][propertyComponents[0] ?? ""]; + if (queryParameter == null) { + return false; + } + const resolvedQueryParameterType = typeResolver.resolveType({ + type: typeof queryParameter !== "string" ? queryParameter.type : queryParameter, + file + }); + return validate({ + resolvedType: resolvedQueryParameterType + }); +} + export function resolvedTypeHasProperty({ typeResolver, file, @@ -118,10 +165,10 @@ export function resolvedTypeHasProperty({ file: FernFileContext; resolvedType: ResolvedType | undefined; propertyComponents: string[]; - validate: (resolvedType: ResolvedType | undefined) => boolean; + validate: RequestPropertyValidatorFunc; }): boolean { if (propertyComponents.length === 0) { - return validate(resolvedType); + return validate({ resolvedType }); } const objectSchema = maybeObjectSchema(resolvedType); if (objectSchema == null) { @@ -199,7 +246,7 @@ function objectSchemaHasProperty({ file: FernFileContext; objectSchema: RawSchemas.ObjectSchema; propertyComponents: string[]; - validate: (resolvedType: ResolvedType | undefined) => boolean; + validate: RequestPropertyValidatorFunc; }): boolean { const property = getPropertyTypeFromObjectSchema({ typeResolver, diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenPropertiesSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenPropertiesSchema.ts deleted file mode 100644 index 6d72a487bae..00000000000 --- a/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenPropertiesSchema.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from "zod"; - -export const OAuthAccessTokenPropertiesSchema = z.strictObject({ - "access-token": z.string(), - "expires-in": z.optional(z.string()), - "refresh-token": z.optional(z.string()) -}); - -export type OAuthAccessTokenPropertiesSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenRequestPropertiesSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenRequestPropertiesSchema.ts new file mode 100644 index 00000000000..1fd12bfad8f --- /dev/null +++ b/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenRequestPropertiesSchema.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +export const OAuthAccessTokenRequestPropertiesSchema = z.strictObject({ + "client-id": z.optional(z.string()).describe("The property name for the client ID."), + "client-secret": z.optional(z.string()).describe("The property name for the client secret."), + scopes: z.optional(z.string()).describe("The property name for the scopes.") +}); + +export type OAuthAccessTokenRequestPropertiesSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenResponsePropertiesSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenResponsePropertiesSchema.ts new file mode 100644 index 00000000000..f5031f29741 --- /dev/null +++ b/packages/cli/yaml/yaml-schema/src/schemas/OAuthAccessTokenResponsePropertiesSchema.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +export const OAuthAccessTokenResponsePropertiesSchema = z.strictObject({ + "access-token": z.optional(z.string()).describe("The property name for the access token."), + "expires-in": z.optional(z.string()).describe("The property name for the expires in property."), + "refresh-token": z.optional(z.string()).describe("The property name for the refresh token.") +}); + +export type OAuthAccessTokenResponsePropertiesSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthGetTokenEndpointSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthGetTokenEndpointSchema.ts index 3495aa135a6..08ad35155d1 100644 --- a/packages/cli/yaml/yaml-schema/src/schemas/OAuthGetTokenEndpointSchema.ts +++ b/packages/cli/yaml/yaml-schema/src/schemas/OAuthGetTokenEndpointSchema.ts @@ -1,9 +1,11 @@ import { z } from "zod"; -import { OAuthAccessTokenPropertiesSchema } from "./OAuthAccessTokenPropertiesSchema"; +import { OAuthAccessTokenRequestPropertiesSchema } from "./OAuthAccessTokenRequestPropertiesSchema"; +import { OAuthAccessTokenResponsePropertiesSchema } from "./OAuthAccessTokenResponsePropertiesSchema"; export const OAuthGetTokenEndpointSchema = z.strictObject({ endpoint: z.string().describe("The endpoint to get the access token, such as 'auth.get_token')"), - "response-properties": OAuthAccessTokenPropertiesSchema + "request-properties": OAuthAccessTokenRequestPropertiesSchema.optional(), + "response-properties": OAuthAccessTokenResponsePropertiesSchema.optional() }); export type OAuthGetTokenEndpointSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenEndpointSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenEndpointSchema.ts index 20536558741..e3371adde4c 100644 --- a/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenEndpointSchema.ts +++ b/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenEndpointSchema.ts @@ -1,11 +1,10 @@ import { z } from "zod"; -import { OAuthAccessTokenPropertiesSchema } from "./OAuthAccessTokenPropertiesSchema"; -import { OAuthRefreshTokenPropertiesSchema } from "./OAuthRefreshTokenPropertiesSchema"; +import { OAuthAccessTokenResponsePropertiesSchema } from "./OAuthAccessTokenResponsePropertiesSchema"; +import { OAuthRefreshTokenRequestPropertiesSchema } from "./OAuthRefreshTokenRequestPropertiesSchema"; export const OAuthRefreshTokenEndpointSchema = z.strictObject({ endpoint: z.string().describe("The endpoint to refresh the access token, such as 'auth.refresh_token')"), - "request-properties": OAuthRefreshTokenPropertiesSchema, - "response-properties": OAuthAccessTokenPropertiesSchema + "request-properties": OAuthRefreshTokenRequestPropertiesSchema.optional(), + "response-properties": OAuthAccessTokenResponsePropertiesSchema.optional() }); - export type OAuthRefreshTokenEndpointSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenPropertiesSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenPropertiesSchema.ts deleted file mode 100644 index 0a03d6c928b..00000000000 --- a/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenPropertiesSchema.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { z } from "zod"; - -export const OAuthRefreshTokenPropertiesSchema = z.strictObject({ - "refresh-token": z.string() -}); - -export type OAuthRefreshTokenPropertiesSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenRequestPropertiesSchema.ts b/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenRequestPropertiesSchema.ts new file mode 100644 index 00000000000..7555db91299 --- /dev/null +++ b/packages/cli/yaml/yaml-schema/src/schemas/OAuthRefreshTokenRequestPropertiesSchema.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +export const OAuthRefreshTokenRequestPropertiesSchema = z.strictObject({ + "refresh-token": z.string().describe("The property name for the refresh token.") +}); + +export type OAuthRefreshTokenRequestPropertiesSchema = z.infer; diff --git a/packages/cli/yaml/yaml-schema/src/schemas/index.ts b/packages/cli/yaml/yaml-schema/src/schemas/index.ts index 2b854f9c66b..6422a1af478 100644 --- a/packages/cli/yaml/yaml-schema/src/schemas/index.ts +++ b/packages/cli/yaml/yaml-schema/src/schemas/index.ts @@ -39,9 +39,12 @@ export { HttpResponseSchema } from "./HttpResponseSchema"; export { HttpResponseStreamSchema } from "./HttpResponseStreamSchema"; export { HttpServiceSchema } from "./HttpServiceSchema"; export { MultipleBaseUrlsEnvironmentSchema } from "./MultipleBaseUrlsEnvironmentSchema"; +export { OAuthAccessTokenRequestPropertiesSchema } from "./OAuthAccessTokenRequestPropertiesSchema"; +export { OAuthAccessTokenResponsePropertiesSchema } from "./OAuthAccessTokenResponsePropertiesSchema"; export { OAuthClientCredentialsSchema } from "./OAuthClientCredentialsSchema"; export { OAuthGetTokenEndpointSchema } from "./OAuthGetTokenEndpointSchema"; export { OAuthRefreshTokenEndpointSchema } from "./OAuthRefreshTokenEndpointSchema"; +export { OAuthRefreshTokenRequestPropertiesSchema } from "./OAuthRefreshTokenRequestPropertiesSchema"; export { OAuthSchemeSchema } from "./OAuthSchemeSchema"; export { ObjectPropertySchema } from "./ObjectPropertySchema"; export { ObjectSchema } from "./ObjectSchema"; diff --git a/test-definitions/fern/apis/oauth-client-credentials-default/definition/api.yml b/test-definitions/fern/apis/oauth-client-credentials-default/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/test-definitions/fern/apis/oauth-client-credentials-default/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/test-definitions/fern/apis/oauth-client-credentials-default/definition/auth.yml b/test-definitions/fern/apis/oauth-client-credentials-default/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/test-definitions/fern/apis/oauth-client-credentials-default/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/generators.yml b/test-definitions/fern/apis/oauth-client-credentials-default/generators.yml similarity index 100% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/generators.yml rename to test-definitions/fern/apis/oauth-client-credentials-default/generators.yml diff --git a/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/api.yml b/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/api.yml index 02369d2d955..3869123994b 100644 --- a/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/api.yml +++ b/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials-environment-variables -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/auth.yml b/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/auth.yml index e52e3cee177..b0dc81c642a 100644 --- a/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/auth.yml +++ b/test-definitions/fern/apis/oauth-client-credentials-environment-variables/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: @@ -28,7 +28,7 @@ service: refreshToken: path: /token method: POST - request: + request: name: RefreshTokenRequest body: properties: diff --git a/test-definitions/fern/apis/oauth-client-credentials/definition/api.yml b/test-definitions/fern/apis/oauth-client-credentials/definition/api.yml index 5c43f960009..3ca293f63ed 100644 --- a/test-definitions/fern/apis/oauth-client-credentials/definition/api.yml +++ b/test-definitions/fern/apis/oauth-client-credentials/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/test-definitions/fern/apis/oauth-client-credentials/definition/auth.yml b/test-definitions/fern/apis/oauth-client-credentials/definition/auth.yml index e52e3cee177..e7887dddb67 100644 --- a/test-definitions/fern/apis/oauth-client-credentials/definition/auth.yml +++ b/test-definitions/fern/apis/oauth-client-credentials/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: diff --git a/yarn.lock b/yarn.lock index af9b56d9897..6055da26009 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4519,6 +4519,7 @@ __metadata: organize-imports-cli: ^0.10.0 prettier: ^2.7.1 strip-ansi: ^7.1.0 + terminal-link: ^3.0.0 typescript: 4.6.4 languageName: unknown linkType: soft From 2b538d64626029341e9aed1f9beea671f19faca8 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 9 May 2024 11:48:40 -0400 Subject: [PATCH 2/6] Fix test helper function --- .../valid-oauth/__test__/valid-oauth.test.ts | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts index 778672744a2..b0d42d32102 100644 --- a/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts +++ b/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/valid-oauth.test.ts @@ -69,20 +69,25 @@ describe("valid-oauth", () => { const expectedViolations: ValidationViolation[] = [ { message: - "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_id'; expected '$request.client-id' instead. For details, see the docs.", + "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_id'; expected '$request.client-id' instead.", nodePath: ["service", "endpoints", "getToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_secret'; expected '$request.client-secret' instead. For details, see the docs.", + "OAuth configuration for endpoint getToken cannot reference nested $request properties like '$request.credentials.client_secret'; expected '$request.client-secret' instead.", nodePath: ["service", "endpoints", "getToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" } ]; - expect(violations).toEqual(expectedViolations); + expect(() => + validateOAuthRuleViolations({ + expected: expectedViolations, + actual: violations + }) + ).not.toThrow(); }); it("invalid-missing", async () => { @@ -98,48 +103,53 @@ describe("valid-oauth", () => { const expectedViolations: ValidationViolation[] = [ { message: - "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'access-token' $response.accessToken, which is not a valid 'access-token' type. For details, see the docs.", + "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'access-token' $response.accessToken, which is not a valid 'access-token' type.", nodePath: ["service", "endpoints", "getTokenWithClientCredentials"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'expires-in' $response.expiresIn, which is not a valid 'expires-in' type. For details, see the docs.", + "OAuth configuration for endpoint getTokenWithClientCredentials specifies 'expires-in' $response.expiresIn, which is not a valid 'expires-in' type.", nodePath: ["service", "endpoints", "getTokenWithClientCredentials"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $request.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type. For details, see the docs.", + "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $request.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'access-token' $response.accessTokenDoesNotExist, which is not a valid 'access-token' type. For details, see the docs.", + "OAuth configuration for endpoint refreshToken specifies 'access-token' $response.accessTokenDoesNotExist, which is not a valid 'access-token' type.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'expires-in' $response.expiresInDoesNotExist, which is not a valid 'expires-in' type. For details, see the docs.", + "OAuth configuration for endpoint refreshToken specifies 'expires-in' $response.expiresInDoesNotExist, which is not a valid 'expires-in' type.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $response.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type. For details, see the docs.", + "OAuth configuration for endpoint refreshToken specifies 'refresh-token' $response.refreshTokenDoesNotExist, which is not a valid 'refresh-token' type.", nodePath: ["service", "endpoints", "refreshToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" } ]; - expect(violations).toEqual(expectedViolations); + expect(() => + validateOAuthRuleViolations({ + expected: expectedViolations, + actual: violations + }) + ).not.toThrow(); }); it("invalid-types", async () => { @@ -155,26 +165,49 @@ describe("valid-oauth", () => { const expectedViolations: ValidationViolation[] = [ { message: - "OAuth configuration for endpoint getToken is missing a valid client-id, such as '$request.client_id'. For details, see the docs.", + "OAuth configuration for endpoint getToken is missing a valid client-id, such as '$request.client_id'.", nodePath: ["service", "endpoints", "getToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint getToken is missing a valid client-secret, such as '$request.client_secret'. For details, see the docs.", + "OAuth configuration for endpoint getToken is missing a valid client-secret, such as '$request.client_secret'.", nodePath: ["service", "endpoints", "getToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" }, { message: - "OAuth configuration for endpoint getToken specifies 'scopes' $request.scopes, which is not a valid 'scopes' type. For details, see the docs.", + "OAuth configuration for endpoint getToken specifies 'scopes' $request.scopes, which is not a valid 'scopes' type.", nodePath: ["service", "endpoints", "getToken"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" } ]; - expect(violations).toEqual(expectedViolations); + expect(() => + validateOAuthRuleViolations({ + expected: expectedViolations, + actual: violations + }) + ).not.toThrow(); }); }); + +// validateOAuthRuleViolations ensures all of the expected rule violations match, +// but only verifies the message prefix because the output differs in certain +// terminal environments. +function validateOAuthRuleViolations({ + expected, + actual +}: { + expected: ValidationViolation[]; + actual: ValidationViolation[]; +}): void { + expected.forEach((expected, index) => { + const actualMessage = actual?.[index]?.message; + expect(actualMessage).toBeDefined(); + expect(actualMessage?.startsWith(expected.message)).toBe(true); + }); + expect(actual.map(({ message, ...rest }) => rest)).toEqual(actual.map(({ message, ...rest }) => rest)); +} From 2eb77c2291ce316b5a08b749498603e0c2cdda56 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 9 May 2024 12:00:23 -0400 Subject: [PATCH 3/6] Update express snapshot for api-wide-base-path --- .../api/resources/service/service/ServiceService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed/ts-express/api-wide-base-path/api/resources/service/service/ServiceService.ts b/seed/ts-express/api-wide-base-path/api/resources/service/service/ServiceService.ts index 1c2a07e4ebf..c728adf5535 100644 --- a/seed/ts-express/api-wide-base-path/api/resources/service/service/ServiceService.ts +++ b/seed/ts-express/api-wide-base-path/api/resources/service/service/ServiceService.ts @@ -46,7 +46,7 @@ export class ServiceService { this.router.post("/:endpointParam/:resourceParam", async (req, res, next) => { try { await this.methods.post(req as any, { - send: async (responseBody) => { + send: async () => { res.sendStatus(204); }, cookie: res.cookie.bind(res), From c4d26e616d5e4c62c4196029a076885dfb331473 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 9 May 2024 12:18:50 -0400 Subject: [PATCH 4/6] Add oauth-client-credentials-default testdata --- .../.gitignore | 477 +++++++ .../.inputs/config.json | 24 + .../.inputs/ir.json | 697 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../snippet-templates.json | 0 .../snippet.json | 0 ...dOauthClientCredentialsDefault.Test.csproj | 24 + .../Auth/TokenResponse.cs | 12 + .../SeedOauthClientCredentialsDefault.csproj | 12 + .../.gitignore | 477 +++++++ .../.inputs/config.json | 31 + .../.inputs/ir.json | 697 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../snippet-templates.json | 0 .../snippet.json | 0 ...dOauthClientCredentialsDefault.Test.csproj | 24 + .../TestClient.cs | 3 + .../Auth/AuthClient.cs | 15 + .../Auth/Types/TokenResponse.cs | 12 + .../Core/ClientOptions.cs | 24 + .../Core/RawClient.cs | 118 ++ .../SeedOauthClientCredentialsDefault.csproj | 12 + ...SeedOauthClientCredentialsDefaultClient.cs | 29 + .../.inputs/config.json | 20 + .../.inputs/ir.json | 1115 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../__init__.py | 6 + .../core/__init__.py | 25 + .../core/abstract_fern_service.py | 11 + .../core/datetime_utils.py | 28 + .../core/exceptions/__init__.py | 13 + .../core/exceptions/fern_http_exception.py | 20 + .../core/exceptions/handlers.py | 32 + .../core/exceptions/unauthorized.py | 15 + .../core/pydantic_utilities.py | 12 + .../core/route_args.py | 63 + .../core/security/__init__.py | 5 + .../core/security/bearer.py | 22 + .../register.py | 44 + .../resources/__init__.py | 6 + .../resources/auth/__init__.py | 6 + .../resources/auth/service/__init__.py | 6 + .../auth/service/get_token_request.py | 25 + .../resources/auth/service/service.py | 74 + .../resources/auth/types/__init__.py | 5 + .../resources/auth/types/token_response.py | 28 + .../security.py | 11 + .../snippet-templates.json | 0 .../snippet.json | 0 .../.github/workflows/ci.yml | 27 + .../.inputs/config.json | 24 + .../.inputs/ir.json | 1145 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../oauth-client-credentials-default/auth.go | 55 + .../core/stringer.go | 13 + .../core/time.go | 137 ++ .../oauth-client-credentials-default/go.mod | 3 + .../oauth-client-credentials-default/go.sum | 0 .../snippet-templates.json | 0 .../snippet.json | 0 .../.github/workflows/ci.yml | 27 + .../.inputs/config.json | 24 + .../.inputs/ir.json | 1145 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../oauth-client-credentials-default/auth.go | 21 + .../core/stringer.go | 13 + .../core/time.go | 137 ++ .../oauth-client-credentials-default/go.mod | 3 + .../oauth-client-credentials-default/go.sum | 0 .../snippet-templates.json | 0 .../snippet.json | 0 .../.github/workflows/ci.yml | 27 + .../.inputs/config.json | 24 + .../.inputs/ir.json | 1145 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../oauth-client-credentials-default/auth.go | 73 + .../auth/client.go | 67 + .../client/client.go | 33 + .../client/client_test.go | 45 + .../core/core.go | 280 ++++ .../core/core_test.go | 284 ++++ .../core/query.go | 219 +++ .../core/query_test.go | 160 +++ .../core/request_option.go | 88 ++ .../core/retrier.go | 166 +++ .../core/stringer.go | 13 + .../core/time.go | 137 ++ .../oauth-client-credentials-default/go.mod | 9 + .../oauth-client-credentials-default/go.sum | 14 + .../option/request_option.go | 41 + .../pointer.go | 132 ++ .../snippet-templates.json | 0 .../snippet.json | 14 + .../.github/workflows/ci.yml | 61 + .../.gitignore | 24 + .../.inputs/config.json | 31 + .../.inputs/ir.json | 694 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../build.gradle | 67 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43462 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../oauth-client-credentials-default/gradlew | 249 ++++ .../gradlew.bat | 92 ++ .../settings.gradle | 0 .../snippet-templates.json | 0 .../snippet.json | 0 .../core/DateTimeDeserializer.java | 55 + .../core/ObjectMappers.java | 36 + .../model/auth/TokenResponse.java | 108 ++ .../.github/workflows/ci.yml | 61 + .../.gitignore | 24 + .../.inputs/config.json | 31 + .../.inputs/ir.json | 694 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../build.gradle | 70 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../oauth-client-credentials-default/gradlew | 249 ++++ .../gradlew.bat | 92 ++ .../sample-app/build.gradle | 19 + .../sample-app/src/main/java/sample/App.java | 13 + .../settings.gradle | 1 + .../snippet-templates.json | 0 .../snippet.json | 0 ...edOauthClientCredentialsDefaultClient.java | 28 + ...ClientCredentialsDefaultClientBuilder.java | 34 + .../core/ApiError.java | 28 + .../core/ClientOptions.java | 100 ++ .../core/DateTimeDeserializer.java | 55 + .../core/Environment.java | 20 + .../core/MediaTypes.java | 13 + .../core/ObjectMappers.java | 36 + .../core/RequestOptions.java | 71 + .../core/RetryInterceptor.java | 78 ++ .../core/Stream.java | 97 ++ .../core/Suppliers.java | 23 + .../resources/auth/AuthClient.java | 69 + .../auth/requests/GetTokenRequest.java | 128 ++ .../resources/auth/types/TokenResponse.java | 123 ++ .../TestClient.java | 11 + .../.inputs/config.json | 20 + .../.inputs/ir.json | 694 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../core/APIException.java | 10 + .../core/BearerAuth.java | 30 + .../core/DateTimeDeserializer.java | 56 + .../core/ObjectMappers.java | 41 + .../resources/auth/AuthService.java | 23 + .../auth/requests/GetTokenRequest.java | 121 ++ .../resources/auth/types/TokenResponse.java | 116 ++ .../snippet-templates.json | 0 .../snippet.json | 0 .../.inputs/config.json | 20 + .../.inputs/ir.json | 699 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../openapi.yml | 55 + .../snippet-templates.json | 0 .../snippet.json | 0 .../.inputs/config.json | 20 + .../.inputs/ir.json | 699 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../snippet-templates.json | 0 .../snippet.json | 0 .../.github/workflows/ci.yml | 60 + .../.gitignore | 4 + .../.inputs/config.json | 30 + .../.inputs/ir.json | 1115 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../README.md | 0 .../pyproject.toml | 30 + .../snippet-templates.json | 0 .../snippet.json | 0 .../__init__.py | 5 + .../core/__init__.py | 6 + .../core/datetime_utils.py | 28 + .../core/pydantic_utilities.py | 12 + .../oauth_client_credentials_default/py.typed | 0 .../resources/__init__.py | 6 + .../resources/auth/__init__.py | 5 + .../resources/auth/token_response.py | 28 + .../tests/custom/test_client.py | 6 + .../.github/workflows/ci.yml | 60 + .../.gitignore | 4 + .../.inputs/config.json | 30 + .../.inputs/ir.json | 1143 +++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../README.md | 0 .../pyproject.toml | 33 + .../snippet-templates.json | 105 ++ .../snippet.json | 16 + .../src/seed/__init__.py | 7 + .../src/seed/auth/__init__.py | 5 + .../src/seed/auth/client.py | 164 +++ .../src/seed/auth/types/__init__.py | 5 + .../src/seed/auth/types/token_response.py | 30 + .../src/seed/client.py | 141 ++ .../src/seed/core/__init__.py | 27 + .../src/seed/core/api_error.py | 15 + .../src/seed/core/client_wrapper.py | 69 + .../src/seed/core/datetime_utils.py | 28 + .../src/seed/core/file.py | 38 + .../src/seed/core/http_client.py | 130 ++ .../src/seed/core/jsonable_encoder.py | 99 ++ .../src/seed/core/oauth_token_provider.py | 30 + .../src/seed/core/pydantic_utilities.py | 12 + .../src/seed/core/remove_none_from_dict.py | 11 + .../src/seed/core/request_options.py | 32 + .../src/seed/py.typed | 0 .../src/seed/version.py | 4 + .../tests/custom/test_client.py | 6 + .../.inputs/config.json | 20 + .../.inputs/ir.json | 694 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../.rubocop.yml | 36 + .../oauth-client-credentials-default/Gemfile | 9 + .../oauth-client-credentials-default/Rakefile | 12 + .../lib/gemconfig.rb | 14 + ...oauth_client_credentials_default_client.rb | 3 + .../auth/types/token_response.rb | 67 + ..._client_credentials_default_client.gemspec | 21 + .../snippet-templates.json | 0 .../snippet.json | 0 .../test/test_helper.rb | 6 + ...oauth_client_credentials_default_client.rb | 11 + .../.github/workflows/publish.yml | 26 + .../.gitignore | 10 + .../.inputs/config.json | 29 + .../.inputs/ir.json | 694 ++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../.rubocop.yml | 36 + .../oauth-client-credentials-default/Gemfile | 9 + .../README.md | 0 .../oauth-client-credentials-default/Rakefile | 12 + ...n_oauth_client_credentials_default.gemspec | 21 + .../fern_oauth_client_credentials_default.rb | 3 + .../auth/types/token_response.rb | 67 + .../lib/gemconfig.rb | 14 + .../snippet-templates.json | 0 .../snippet.json | 0 ...t_fern_oauth_client_credentials_default.rb | 11 + .../test/test_helper.rb | 6 + .../.inputs/config.json | 23 + .../.inputs/ir.json | 1223 +++++++++++++++++ .../.mock/definition/api.yml | 11 + .../.mock/definition/auth.yml | 23 + .../.mock/fern.config.json | 1 + .../.mock/generators.yml | 1 + .../api/index.ts | 1 + .../api/resources/auth/index.ts | 2 + .../api/resources/auth/service/AuthService.ts | 85 ++ .../api/resources/auth/service/index.ts | 1 + .../auth/service/requests/GetTokenRequest.ts | 9 + .../resources/auth/service/requests/index.ts | 1 + .../api/resources/auth/types/TokenResponse.ts | 11 + .../api/resources/auth/types/index.ts | 1 + .../api/resources/index.ts | 3 + .../core/index.ts | 1 + .../core/schemas/Schema.ts | 94 ++ .../core/schemas/builders/date/date.ts | 65 + .../core/schemas/builders/date/index.ts | 1 + .../core/schemas/builders/enum/enum.ts | 43 + .../core/schemas/builders/enum/index.ts | 1 + .../core/schemas/builders/index.ts | 13 + .../core/schemas/builders/lazy/index.ts | 3 + .../core/schemas/builders/lazy/lazy.ts | 34 + .../core/schemas/builders/lazy/lazyObject.ts | 20 + .../core/schemas/builders/list/index.ts | 1 + .../core/schemas/builders/list/list.ts | 74 + .../builders/literals/booleanLiteral.ts | 29 + .../core/schemas/builders/literals/index.ts | 2 + .../builders/literals/stringLiteral.ts | 29 + .../object-like/getObjectLikeUtils.ts | 79 ++ .../schemas/builders/object-like/index.ts | 2 + .../schemas/builders/object-like/types.ts | 11 + .../core/schemas/builders/object/index.ts | 22 + .../core/schemas/builders/object/object.ts | 333 +++++ .../object/objectWithoutOptionalProperties.ts | 18 + .../core/schemas/builders/object/property.ts | 23 + .../core/schemas/builders/object/types.ts | 72 + .../core/schemas/builders/primitives/any.ts | 4 + .../schemas/builders/primitives/boolean.ts | 25 + .../core/schemas/builders/primitives/index.ts | 5 + .../schemas/builders/primitives/number.ts | 25 + .../schemas/builders/primitives/string.ts | 25 + .../schemas/builders/primitives/unknown.ts | 4 + .../core/schemas/builders/record/index.ts | 2 + .../core/schemas/builders/record/record.ts | 131 ++ .../core/schemas/builders/record/types.ts | 17 + .../builders/schema-utils/JsonError.ts | 9 + .../builders/schema-utils/ParseError.ts | 9 + .../builders/schema-utils/getSchemaUtils.ts | 99 ++ .../schemas/builders/schema-utils/index.ts | 4 + .../schema-utils/stringifyValidationErrors.ts | 8 + .../core/schemas/builders/set/index.ts | 1 + .../core/schemas/builders/set/set.ts | 43 + .../builders/undiscriminated-union/index.ts | 6 + .../builders/undiscriminated-union/types.ts | 10 + .../undiscriminatedUnion.ts | 61 + .../schemas/builders/union/discriminant.ts | 14 + .../core/schemas/builders/union/index.ts | 10 + .../core/schemas/builders/union/types.ts | 26 + .../core/schemas/builders/union/union.ts | 173 +++ .../core/schemas/index.ts | 2 + .../core/schemas/utils/MaybePromise.ts | 1 + .../addQuestionMarksToNullableProperties.ts | 15 + .../utils/createIdentitySchemaCreator.ts | 21 + .../core/schemas/utils/entries.ts | 3 + .../core/schemas/utils/filterObject.ts | 10 + .../utils/getErrorMessageForIncorrectType.ts | 21 + .../core/schemas/utils/isPlainObject.ts | 17 + .../core/schemas/utils/keys.ts | 3 + .../core/schemas/utils/maybeSkipValidation.ts | 39 + .../core/schemas/utils/partition.ts | 12 + .../SeedOauthClientCredentialsDefaultError.ts | 14 + .../errors/index.ts | 1 + .../oauth-client-credentials-default/index.ts | 3 + .../register.ts | 15 + .../serialization/index.ts | 1 + .../serialization/resources/auth/index.ts | 2 + .../resources/auth/service/index.ts | 1 + .../auth/service/requests/GetTokenRequest.ts | 24 + .../resources/auth/service/requests/index.ts | 1 + .../resources/auth/types/TokenResponse.ts | 22 + .../resources/auth/types/index.ts | 1 + .../serialization/resources/index.ts | 3 + .../snippet-templates.json | 0 .../snippet.json | 0 .../.inputs/config.json | 29 + .../.inputs/ir.json | 1223 +++++++++++++++++ 374 files changed, 26739 insertions(+) create mode 100644 seed/csharp-model/oauth-client-credentials-default/.gitignore create mode 100644 seed/csharp-model/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/csharp-model/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/csharp-model/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/csharp-model/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/csharp-model/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/csharp-model/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/csharp-model/oauth-client-credentials-default/snippet.json create mode 100644 seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj create mode 100644 seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/TokenResponse.cs create mode 100644 seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.gitignore create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/snippet.json create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/TestClient.cs create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/Types/TokenResponse.cs create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/ClientOptions.cs create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs create mode 100644 seed/fastapi/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/fastapi/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/fastapi/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/fastapi/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/fastapi/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/fastapi/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/fastapi/oauth-client-credentials-default/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/abstract_fern_service.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/datetime_utils.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/exceptions/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/exceptions/fern_http_exception.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/exceptions/handlers.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/exceptions/unauthorized.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/pydantic_utilities.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/route_args.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/security/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/core/security/bearer.py create mode 100644 seed/fastapi/oauth-client-credentials-default/register.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/service/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/service/get_token_request.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/service/service.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/types/__init__.py create mode 100644 seed/fastapi/oauth-client-credentials-default/resources/auth/types/token_response.py create mode 100644 seed/fastapi/oauth-client-credentials-default/security.py create mode 100644 seed/fastapi/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/fastapi/oauth-client-credentials-default/snippet.json create mode 100644 seed/go-fiber/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/go-fiber/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/go-fiber/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/go-fiber/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/go-fiber/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/go-fiber/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/go-fiber/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/go-fiber/oauth-client-credentials-default/auth.go create mode 100644 seed/go-fiber/oauth-client-credentials-default/core/stringer.go create mode 100644 seed/go-fiber/oauth-client-credentials-default/core/time.go create mode 100644 seed/go-fiber/oauth-client-credentials-default/go.mod create mode 100644 seed/go-fiber/oauth-client-credentials-default/go.sum create mode 100644 seed/go-fiber/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/go-fiber/oauth-client-credentials-default/snippet.json create mode 100644 seed/go-model/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/go-model/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/go-model/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/go-model/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/go-model/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/go-model/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/go-model/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/go-model/oauth-client-credentials-default/auth.go create mode 100644 seed/go-model/oauth-client-credentials-default/core/stringer.go create mode 100644 seed/go-model/oauth-client-credentials-default/core/time.go create mode 100644 seed/go-model/oauth-client-credentials-default/go.mod create mode 100644 seed/go-model/oauth-client-credentials-default/go.sum create mode 100644 seed/go-model/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/go-model/oauth-client-credentials-default/snippet.json create mode 100644 seed/go-sdk/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/go-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/go-sdk/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/go-sdk/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/go-sdk/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/go-sdk/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/go-sdk/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/go-sdk/oauth-client-credentials-default/auth.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/auth/client.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/client/client.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/client/client_test.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/core.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/core_test.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/query.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/query_test.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/request_option.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/retrier.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/stringer.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/core/time.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/go.mod create mode 100644 seed/go-sdk/oauth-client-credentials-default/go.sum create mode 100644 seed/go-sdk/oauth-client-credentials-default/option/request_option.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/pointer.go create mode 100644 seed/go-sdk/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/go-sdk/oauth-client-credentials-default/snippet.json create mode 100644 seed/java-model/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/java-model/oauth-client-credentials-default/.gitignore create mode 100644 seed/java-model/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/java-model/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/java-model/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/java-model/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/java-model/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/java-model/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/java-model/oauth-client-credentials-default/build.gradle create mode 100644 seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar create mode 100644 seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties create mode 100755 seed/java-model/oauth-client-credentials-default/gradlew create mode 100644 seed/java-model/oauth-client-credentials-default/gradlew.bat create mode 100644 seed/java-model/oauth-client-credentials-default/settings.gradle create mode 100644 seed/java-model/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/java-model/oauth-client-credentials-default/snippet.json create mode 100644 seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java create mode 100644 seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java create mode 100644 seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/model/auth/TokenResponse.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/java-sdk/oauth-client-credentials-default/.gitignore create mode 100644 seed/java-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/java-sdk/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/java-sdk/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/java-sdk/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/java-sdk/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/java-sdk/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/java-sdk/oauth-client-credentials-default/build.gradle create mode 100644 seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar create mode 100644 seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties create mode 100755 seed/java-sdk/oauth-client-credentials-default/gradlew create mode 100644 seed/java-sdk/oauth-client-credentials-default/gradlew.bat create mode 100644 seed/java-sdk/oauth-client-credentials-default/sample-app/build.gradle create mode 100644 seed/java-sdk/oauth-client-credentials-default/sample-app/src/main/java/sample/App.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/settings.gradle create mode 100644 seed/java-sdk/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/java-sdk/oauth-client-credentials-default/snippet.json create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClientBuilder.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ApiError.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ClientOptions.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Environment.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/MediaTypes.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RequestOptions.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RetryInterceptor.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Stream.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Suppliers.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/AuthClient.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/requests/GetTokenRequest.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/types/TokenResponse.java create mode 100644 seed/java-sdk/oauth-client-credentials-default/src/test/java/com/seed/oauthClientCredentialsDefault/TestClient.java create mode 100644 seed/java-spring/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/java-spring/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/java-spring/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/java-spring/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/java-spring/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/java-spring/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/java-spring/oauth-client-credentials-default/core/APIException.java create mode 100644 seed/java-spring/oauth-client-credentials-default/core/BearerAuth.java create mode 100644 seed/java-spring/oauth-client-credentials-default/core/DateTimeDeserializer.java create mode 100644 seed/java-spring/oauth-client-credentials-default/core/ObjectMappers.java create mode 100644 seed/java-spring/oauth-client-credentials-default/resources/auth/AuthService.java create mode 100644 seed/java-spring/oauth-client-credentials-default/resources/auth/requests/GetTokenRequest.java create mode 100644 seed/java-spring/oauth-client-credentials-default/resources/auth/types/TokenResponse.java create mode 100644 seed/java-spring/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/java-spring/oauth-client-credentials-default/snippet.json create mode 100644 seed/openapi/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/openapi/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/openapi/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/openapi/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/openapi/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/openapi/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/openapi/oauth-client-credentials-default/openapi.yml create mode 100644 seed/openapi/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/openapi/oauth-client-credentials-default/snippet.json create mode 100644 seed/postman/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/postman/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/postman/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/postman/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/postman/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/postman/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/postman/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/postman/oauth-client-credentials-default/snippet.json create mode 100644 seed/pydantic/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/pydantic/oauth-client-credentials-default/.gitignore create mode 100644 seed/pydantic/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/pydantic/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/pydantic/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/pydantic/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/pydantic/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/pydantic/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/pydantic/oauth-client-credentials-default/README.md create mode 100644 seed/pydantic/oauth-client-credentials-default/pyproject.toml create mode 100644 seed/pydantic/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/pydantic/oauth-client-credentials-default/snippet.json create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/__init__.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/__init__.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/datetime_utils.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/pydantic_utilities.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/py.typed create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/__init__.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/__init__.py create mode 100644 seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/token_response.py create mode 100644 seed/pydantic/oauth-client-credentials-default/tests/custom/test_client.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/.github/workflows/ci.yml create mode 100644 seed/python-sdk/oauth-client-credentials-default/.gitignore create mode 100644 seed/python-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/python-sdk/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/python-sdk/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/python-sdk/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/python-sdk/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/python-sdk/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/python-sdk/oauth-client-credentials-default/README.md create mode 100644 seed/python-sdk/oauth-client-credentials-default/pyproject.toml create mode 100644 seed/python-sdk/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/python-sdk/oauth-client-credentials-default/snippet.json create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/__init__.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/auth/__init__.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/auth/client.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/__init__.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/token_response.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/client.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/__init__.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/api_error.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/client_wrapper.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/datetime_utils.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/file.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/http_client.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/jsonable_encoder.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/oauth_token_provider.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/pydantic_utilities.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/remove_none_from_dict.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/core/request_options.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/py.typed create mode 100644 seed/python-sdk/oauth-client-credentials-default/src/seed/version.py create mode 100644 seed/python-sdk/oauth-client-credentials-default/tests/custom/test_client.py create mode 100644 seed/ruby-model/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/ruby-model/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/ruby-model/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/ruby-model/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/ruby-model/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/ruby-model/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/ruby-model/oauth-client-credentials-default/.rubocop.yml create mode 100644 seed/ruby-model/oauth-client-credentials-default/Gemfile create mode 100644 seed/ruby-model/oauth-client-credentials-default/Rakefile create mode 100644 seed/ruby-model/oauth-client-credentials-default/lib/gemconfig.rb create mode 100644 seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client.rb create mode 100644 seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client/auth/types/token_response.rb create mode 100644 seed/ruby-model/oauth-client-credentials-default/seed_oauth_client_credentials_default_client.gemspec create mode 100644 seed/ruby-model/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/ruby-model/oauth-client-credentials-default/snippet.json create mode 100644 seed/ruby-model/oauth-client-credentials-default/test/test_helper.rb create mode 100644 seed/ruby-model/oauth-client-credentials-default/test/test_seed_oauth_client_credentials_default_client.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.github/workflows/publish.yml create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.gitignore create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/.rubocop.yml create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/Gemfile create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/README.md create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/Rakefile create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/types/token_response.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/gemconfig.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/snippet.json create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/test/test_fern_oauth_client_credentials_default.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/test/test_helper.rb create mode 100644 seed/ts-express/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/ts-express/oauth-client-credentials-default/.inputs/ir.json create mode 100644 seed/ts-express/oauth-client-credentials-default/.mock/definition/api.yml create mode 100644 seed/ts-express/oauth-client-credentials-default/.mock/definition/auth.yml create mode 100644 seed/ts-express/oauth-client-credentials-default/.mock/fern.config.json create mode 100644 seed/ts-express/oauth-client-credentials-default/.mock/generators.yml create mode 100644 seed/ts-express/oauth-client-credentials-default/api/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/AuthService.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/GetTokenRequest.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/TokenResponse.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/api/resources/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/Schema.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/date.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/enum.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazy.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazyObject.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/list.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/booleanLiteral.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/stringLiteral.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/getObjectLikeUtils.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/types.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/object.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/objectWithoutOptionalProperties.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/property.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/types.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/any.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/boolean.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/number.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/string.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/unknown.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/record.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/types.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/JsonError.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/ParseError.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/getSchemaUtils.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/stringifyValidationErrors.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/set.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/types.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/undiscriminatedUnion.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/discriminant.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/types.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/union.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/MaybePromise.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/addQuestionMarksToNullableProperties.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/createIdentitySchemaCreator.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/entries.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/filterObject.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/getErrorMessageForIncorrectType.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/isPlainObject.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/keys.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/maybeSkipValidation.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/core/schemas/utils/partition.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/errors/SeedOauthClientCredentialsDefaultError.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/errors/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/register.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/GetTokenRequest.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/TokenResponse.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/serialization/resources/index.ts create mode 100644 seed/ts-express/oauth-client-credentials-default/snippet-templates.json create mode 100644 seed/ts-express/oauth-client-credentials-default/snippet.json create mode 100644 seed/ts-sdk/oauth-client-credentials-default/.inputs/config.json create mode 100644 seed/ts-sdk/oauth-client-credentials-default/.inputs/ir.json diff --git a/seed/csharp-model/oauth-client-credentials-default/.gitignore b/seed/csharp-model/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..9965de29662 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.gitignore @@ -0,0 +1,477 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk diff --git a/seed/csharp-model/oauth-client-credentials-default/.inputs/config.json b/seed/csharp-model/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..be1f2437d42 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,24 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": null + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/.inputs/ir.json b/seed/csharp-model/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..b9c7c82a6f7 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,697 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/.mock/definition/api.yml b/seed/csharp-model/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/csharp-model/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/.mock/fern.config.json b/seed/csharp-model/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml b/seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/csharp-model/oauth-client-credentials-default/snippet-templates.json b/seed/csharp-model/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/csharp-model/oauth-client-credentials-default/snippet.json b/seed/csharp-model/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj new file mode 100644 index 00000000000..17cab683ff6 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + + false + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/TokenResponse.cs b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/TokenResponse.cs new file mode 100644 index 00000000000..c81aaefcc73 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/TokenResponse.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace SeedOauthClientCredentialsDefault; + +public class TokenResponse +{ + [JsonPropertyName("access_token")] + public string AccessToken { get; init; } + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; init; } +} diff --git a/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj new file mode 100644 index 00000000000..6b0a60236b2 --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -0,0 +1,12 @@ + + + + net7.0 + enable + + + + + + + \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.gitignore b/seed/csharp-sdk/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..9965de29662 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.gitignore @@ -0,0 +1,477 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/csharp-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..27b20c665dc --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,31 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "maven", + "registryUrl": "", + "coordinate": "com.fern:oauth-client-credentials-default", + "usernameEnvironmentVariable": "", + "passwordEnvironmentVariable": "", + "signature": null + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/csharp-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..b9c7c82a6f7 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,697 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/api.yml b/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.mock/fern.config.json b/seed/csharp-sdk/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/.mock/generators.yml b/seed/csharp-sdk/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/snippet-templates.json b/seed/csharp-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/csharp-sdk/oauth-client-credentials-default/snippet.json b/seed/csharp-sdk/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj new file mode 100644 index 00000000000..17cab683ff6 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/SeedOauthClientCredentialsDefault.Test.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + + false + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/TestClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/TestClient.cs new file mode 100644 index 00000000000..5121aaf0113 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault.Test/TestClient.cs @@ -0,0 +1,3 @@ +namespace SeedOauthClientCredentialsDefault.Test; + +public class TestClient { } diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs new file mode 100644 index 00000000000..3066d5dad4a --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs @@ -0,0 +1,15 @@ +using SeedOauthClientCredentialsDefault; + +namespace SeedOauthClientCredentialsDefault; + +public class AuthClient +{ + private RawClient _client; + + public AuthClient(RawClient client) + { + _client = client; + } + + public async void GetTokenAsync() { } +} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/Types/TokenResponse.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/Types/TokenResponse.cs new file mode 100644 index 00000000000..c81aaefcc73 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/Types/TokenResponse.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace SeedOauthClientCredentialsDefault; + +public class TokenResponse +{ + [JsonPropertyName("access_token")] + public string AccessToken { get; init; } + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; init; } +} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/ClientOptions.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/ClientOptions.cs new file mode 100644 index 00000000000..d9d21a4e243 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/ClientOptions.cs @@ -0,0 +1,24 @@ +namespace SeedOauthClientCredentialsDefault; + +public partial class ClientOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; init; } + + /// + /// The http client used to make requests. + /// + public HttpClient HttpClient { get; init; } = new HttpClient(); + + /// + /// The http client used to make requests. + /// + public int MaxRetries { get; init; } = 2; + + /// + /// The timeout for the request in seconds. + /// + public int TimeoutInSeconds { get; init; } = 30; +} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs new file mode 100644 index 00000000000..98ad13e5db7 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs @@ -0,0 +1,118 @@ +using System.Text; +using System.Text.Json; + +namespace SeedOauthClientCredentialsDefault; + +#nullable enable + +/// +/// Utility class for making raw HTTP requests to the API. +/// +public class RawClient +{ + /// + /// The http client used to make requests. + /// + private readonly ClientOptions _clientOptions; + + /// + /// Global headers to be sent with every request. + /// + private readonly Dictionary _headers; + + public RawClient(Dictionary headers, ClientOptions clientOptions) + { + _clientOptions = clientOptions; + _headers = headers; + } + + public async Task MakeRequestAsync( + HttpMethod method, + string path, + ApiRequest request + ) + { + var httpRequest = new HttpRequestMessage(method, this.BuildUrl(path, request.Query)); + if (request.ContentType != null) + { + request.Headers.Add("Content-Type", request.ContentType); + } + // Add global headers to the request + foreach (var (key, value) in _headers) + { + httpRequest.Headers.Add(key, value); + } + // Add request headers to the request + foreach (var (key, value) in request.Headers) + { + httpRequest.Headers.Add(key, value); + } + // Add the request body to the request + if (request.Body != null) + { + httpRequest.Content = new StringContent( + JsonSerializer.Serialize(request.Body), + Encoding.UTF8, + "application/json" + ); + } + // Send the request + HttpResponseMessage response = await _clientOptions.HttpClient.SendAsync(httpRequest); + return new ApiResponse { StatusCode = (int)response.StatusCode, Body = response }; + } + + /// + /// The request object to be sent to the API. + /// + public class ApiRequest + { + public string? ContentType = null; + + public object? Body { get; init; } = null; + + public Dictionary Query { get; init; } = new(); + + public Dictionary Headers { get; init; } = new(); + + public object RequestOptions { get; init; } + } + + /// + /// The response object returned from the API. + /// + public class ApiResponse + { + public int StatusCode; + + public HttpResponseMessage Body; + } + + private Dictionary GetHeaders(ApiRequest request) + { + var headers = new Dictionary(); + foreach (var (key, value) in request.Headers) + { + headers.Add(key, value); + } + foreach (var (key, value) in _headers) + { + headers.Add(key, value); + } + return headers; + } + + private string BuildUrl(string path, Dictionary query) + { + var url = $"{_clientOptions.BaseUrl}/{path}"; + if (query.Count > 0) + { + url += "?"; + foreach (var (key, value) in query) + { + url += $"{key}={value}&"; + } + url = url.Substring(0, url.Length - 1); + } + return url; + } +} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj new file mode 100644 index 00000000000..6b0a60236b2 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -0,0 +1,12 @@ + + + + net7.0 + enable + + + + + + + \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs new file mode 100644 index 00000000000..fcc6d667436 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs @@ -0,0 +1,29 @@ +using SeedOauthClientCredentialsDefault; + +namespace SeedOauthClientCredentialsDefault; + +public partial class SeedOauthClientCredentialsDefaultClient +{ + private RawClient _client; + + public SeedOauthClientCredentialsDefaultClient(string token, ClientOptions clientOptions) + { + _client = new RawClient( + new Dictionary { { "X-Fern-Language", "C#" }, }, + clientOptions ?? new ClientOptions() + ); + Auth = new AuthClient(_client); + } + + public AuthClient Auth { get; } + + private string GetFromEnvironmentOrThrow(string env, string message) + { + var value = Environment.GetEnvironmentVariable(env); + if (value == null) + { + throw new Exception(message); + } + return value; + } +} diff --git a/seed/fastapi/oauth-client-credentials-default/.inputs/config.json b/seed/fastapi/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..cd6b9b51711 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,20 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/fastapi/oauth-client-credentials-default/.inputs/ir.json b/seed/fastapi/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..5b243c4c206 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1115 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/fastapi/oauth-client-credentials-default/.mock/definition/api.yml b/seed/fastapi/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/fastapi/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/fastapi/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/fastapi/oauth-client-credentials-default/.mock/fern.config.json b/seed/fastapi/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/fastapi/oauth-client-credentials-default/.mock/generators.yml b/seed/fastapi/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/fastapi/oauth-client-credentials-default/__init__.py b/seed/fastapi/oauth-client-credentials-default/__init__.py new file mode 100644 index 00000000000..72dd3d705a3 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .resources import GetTokenRequest, TokenResponse, auth +from .security import ApiAuth + +__all__ = ["ApiAuth", "GetTokenRequest", "TokenResponse", "auth"] diff --git a/seed/fastapi/oauth-client-credentials-default/core/__init__.py b/seed/fastapi/oauth-client-credentials-default/core/__init__.py new file mode 100644 index 00000000000..f93afe085b4 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/__init__.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +from .datetime_utils import serialize_datetime +from .exceptions import ( + FernHTTPException, + UnauthorizedException, + default_exception_handler, + fern_http_exception_handler, + http_exception_handler, +) +from .pydantic_utilities import pydantic_v1 +from .route_args import route_args +from .security import BearerToken + +__all__ = [ + "BearerToken", + "FernHTTPException", + "UnauthorizedException", + "default_exception_handler", + "fern_http_exception_handler", + "http_exception_handler", + "pydantic_v1", + "route_args", + "serialize_datetime", +] diff --git a/seed/fastapi/oauth-client-credentials-default/core/abstract_fern_service.py b/seed/fastapi/oauth-client-credentials-default/core/abstract_fern_service.py new file mode 100644 index 00000000000..da7c8dc49c4 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/abstract_fern_service.py @@ -0,0 +1,11 @@ +# This file was auto-generated by Fern from our API Definition. + +import abc + +import fastapi + + +class AbstractFernService(abc.ABC): + @classmethod + def _init_fern(cls, router: fastapi.APIRouter) -> None: + ... diff --git a/seed/fastapi/oauth-client-credentials-default/core/datetime_utils.py b/seed/fastapi/oauth-client-credentials-default/core/datetime_utils.py new file mode 100644 index 00000000000..7c9864a944c --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/datetime_utils.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt + + +def serialize_datetime(v: dt.datetime) -> str: + """ + Serialize a datetime including timezone info. + + Uses the timezone info provided if present, otherwise uses the current runtime's timezone info. + + UTC datetimes end in "Z" while all other timezones are represented as offset from UTC, e.g. +05:00. + """ + + def _serialize_zoned_datetime(v: dt.datetime) -> str: + if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None): + # UTC is a special case where we use "Z" at the end instead of "+00:00" + return v.isoformat().replace("+00:00", "Z") + else: + # Delegate to the typical +/- offset format + return v.isoformat() + + if v.tzinfo is not None: + return _serialize_zoned_datetime(v) + else: + local_tz = dt.datetime.now().astimezone().tzinfo + localized_dt = v.replace(tzinfo=local_tz) + return _serialize_zoned_datetime(localized_dt) diff --git a/seed/fastapi/oauth-client-credentials-default/core/exceptions/__init__.py b/seed/fastapi/oauth-client-credentials-default/core/exceptions/__init__.py new file mode 100644 index 00000000000..297d6e06f5f --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/exceptions/__init__.py @@ -0,0 +1,13 @@ +# This file was auto-generated by Fern from our API Definition. + +from .fern_http_exception import FernHTTPException +from .handlers import default_exception_handler, fern_http_exception_handler, http_exception_handler +from .unauthorized import UnauthorizedException + +__all__ = [ + "FernHTTPException", + "UnauthorizedException", + "default_exception_handler", + "fern_http_exception_handler", + "http_exception_handler", +] diff --git a/seed/fastapi/oauth-client-credentials-default/core/exceptions/fern_http_exception.py b/seed/fastapi/oauth-client-credentials-default/core/exceptions/fern_http_exception.py new file mode 100644 index 00000000000..bdf03862487 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/exceptions/fern_http_exception.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import abc +import typing + +import fastapi + + +class FernHTTPException(abc.ABC, fastapi.HTTPException): + def __init__( + self, status_code: int, name: typing.Optional[str] = None, content: typing.Optional[typing.Any] = None + ): + super().__init__(status_code=status_code) + self.name = name + self.status_code = status_code + self.content = content + + def to_json_response(self) -> fastapi.responses.JSONResponse: + content = fastapi.encoders.jsonable_encoder(self.content, exclude_none=True) + return fastapi.responses.JSONResponse(content=content, status_code=self.status_code) diff --git a/seed/fastapi/oauth-client-credentials-default/core/exceptions/handlers.py b/seed/fastapi/oauth-client-credentials-default/core/exceptions/handlers.py new file mode 100644 index 00000000000..fe5ac5419c7 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/exceptions/handlers.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import logging + +import fastapi +import starlette + +from .fern_http_exception import FernHTTPException + + +def fern_http_exception_handler( + request: fastapi.requests.Request, exc: FernHTTPException, skip_log: bool = False +) -> fastapi.responses.JSONResponse: + if not skip_log: + logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc) + return exc.to_json_response() + + +def http_exception_handler( + request: fastapi.requests.Request, exc: starlette.exceptions.HTTPException, skip_log: bool = False +) -> fastapi.responses.JSONResponse: + if not skip_log: + logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc) + return FernHTTPException(status_code=exc.status_code, content=exc.detail).to_json_response() + + +def default_exception_handler( + request: fastapi.requests.Request, exc: Exception, skip_log: bool = False +) -> fastapi.responses.JSONResponse: + if not skip_log: + logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc) + return FernHTTPException(status_code=500, content="Internal Server Error").to_json_response() diff --git a/seed/fastapi/oauth-client-credentials-default/core/exceptions/unauthorized.py b/seed/fastapi/oauth-client-credentials-default/core/exceptions/unauthorized.py new file mode 100644 index 00000000000..32d532e5ef2 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/exceptions/unauthorized.py @@ -0,0 +1,15 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from .fern_http_exception import FernHTTPException + + +class UnauthorizedException(FernHTTPException): + """ + This is the exception that is thrown by Fern when auth is not present on a + request. + """ + + def __init__(self, content: typing.Optional[str] = None) -> None: + super().__init__(status_code=401, content=content) diff --git a/seed/fastapi/oauth-client-credentials-default/core/pydantic_utilities.py b/seed/fastapi/oauth-client-credentials-default/core/pydantic_utilities.py new file mode 100644 index 00000000000..952b5f2a8a8 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/pydantic_utilities.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import pydantic + +IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") + +if IS_PYDANTIC_V2: + import pydantic.v1 as pydantic_v1 # type: ignore # nopycln: import +else: + import pydantic as pydantic_v1 # type: ignore # nopycln: import + +__all__ = ["pydantic_v1"] diff --git a/seed/fastapi/oauth-client-credentials-default/core/route_args.py b/seed/fastapi/oauth-client-credentials-default/core/route_args.py new file mode 100644 index 00000000000..4228e2fe05d --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/route_args.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +import enum +import inspect +import typing + +import typing_extensions + +T = typing.TypeVar("T", bound=typing.Callable[..., typing.Any]) + +FERN_CONFIG_KEY = "__fern" + + +class RouteArgs(typing_extensions.TypedDict): + openapi_extra: typing.Optional[typing.Dict[str, typing.Any]] + tags: typing.Optional[typing.List[typing.Union[str, enum.Enum]]] + include_in_schema: bool + + +DEFAULT_ROUTE_ARGS = RouteArgs(openapi_extra=None, tags=None, include_in_schema=True) + + +def get_route_args(endpoint_function: typing.Callable[..., typing.Any], *, default_tag: str) -> RouteArgs: + unwrapped = inspect.unwrap(endpoint_function, stop=(lambda f: hasattr(f, FERN_CONFIG_KEY))) + route_args = typing.cast(RouteArgs, getattr(unwrapped, FERN_CONFIG_KEY, DEFAULT_ROUTE_ARGS)) + if route_args["tags"] is None: + return RouteArgs( + openapi_extra=route_args["openapi_extra"], + tags=[default_tag], + include_in_schema=route_args["include_in_schema"], + ) + return route_args + + +def route_args( + openapi_extra: typing.Optional[typing.Dict[str, typing.Any]] = None, + tags: typing.Optional[typing.List[typing.Union[str, enum.Enum]]] = None, + include_in_schema: bool = True, +) -> typing.Callable[[T], T]: + """ + this decorator allows you to forward certain args to the FastAPI route decorator. + + usage: + @route_args(openapi_extra=...) + def your_endpoint_method(... + + currently supported args: + - openapi_extra + - tags + + if there's another FastAPI route arg you need to pass through, please + contact the Fern team! + """ + + def decorator(endpoint_function: T) -> T: + setattr( + endpoint_function, + FERN_CONFIG_KEY, + RouteArgs(openapi_extra=openapi_extra, tags=tags, include_in_schema=include_in_schema), + ) + return endpoint_function + + return decorator diff --git a/seed/fastapi/oauth-client-credentials-default/core/security/__init__.py b/seed/fastapi/oauth-client-credentials-default/core/security/__init__.py new file mode 100644 index 00000000000..e69ee6d9c5a --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/security/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .bearer import BearerToken + +__all__ = ["BearerToken"] diff --git a/seed/fastapi/oauth-client-credentials-default/core/security/bearer.py b/seed/fastapi/oauth-client-credentials-default/core/security/bearer.py new file mode 100644 index 00000000000..023342b668d --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/core/security/bearer.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import fastapi + +from ..exceptions import UnauthorizedException + + +class BearerToken: + def __init__(self, token: str): + self.token = token + + +def HTTPBearer(request: fastapi.requests.Request) -> BearerToken: + authorization_header_value = request.headers.get("Authorization") + if not authorization_header_value: + raise UnauthorizedException("Missing Authorization header") + scheme, _, token = authorization_header_value.partition(" ") + if scheme.lower() != "bearer": + raise UnauthorizedException("Authorization header scheme is not bearer") + if not token: + raise UnauthorizedException("Authorization header is missing a token") + return BearerToken(token) diff --git a/seed/fastapi/oauth-client-credentials-default/register.py b/seed/fastapi/oauth-client-credentials-default/register.py new file mode 100644 index 00000000000..4275ccb6bde --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/register.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +import glob +import importlib +import os +import types +import typing + +import fastapi +import starlette +from fastapi import params + +from .core.abstract_fern_service import AbstractFernService +from .core.exceptions import default_exception_handler, fern_http_exception_handler, http_exception_handler +from .core.exceptions.fern_http_exception import FernHTTPException +from .resources.auth.service.service import AbstractAuthService + + +def register( + _app: fastapi.FastAPI, + *, + auth: AbstractAuthService, + dependencies: typing.Optional[typing.Sequence[params.Depends]] = None +) -> None: + _app.include_router(__register_service(auth), dependencies=dependencies) + + _app.add_exception_handler(FernHTTPException, fern_http_exception_handler) + _app.add_exception_handler(starlette.exceptions.HTTPException, http_exception_handler) + _app.add_exception_handler(Exception, default_exception_handler) + + +def __register_service(service: AbstractFernService) -> fastapi.APIRouter: + router = fastapi.APIRouter() + type(service)._init_fern(router) + return router + + +def register_validators(module: types.ModuleType) -> None: + validators_directory: str = os.path.dirname(module.__file__) # type: ignore + for path in glob.glob(os.path.join(validators_directory, "**/*.py"), recursive=True): + if os.path.isfile(path): + relative_path = os.path.relpath(path, start=validators_directory) + module_path = ".".join([module.__name__] + relative_path[:-3].split("/")) + importlib.import_module(module_path) diff --git a/seed/fastapi/oauth-client-credentials-default/resources/__init__.py b/seed/fastapi/oauth-client-credentials-default/resources/__init__.py new file mode 100644 index 00000000000..21863934734 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from . import auth +from .auth import GetTokenRequest, TokenResponse + +__all__ = ["GetTokenRequest", "TokenResponse", "auth"] diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/__init__.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/__init__.py new file mode 100644 index 00000000000..49aef9819c8 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .service import GetTokenRequest +from .types import TokenResponse + +__all__ = ["GetTokenRequest", "TokenResponse"] diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/service/__init__.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/__init__.py new file mode 100644 index 00000000000..28bf519c1de --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .get_token_request import GetTokenRequest +from .service import AbstractAuthService + +__all__ = ["AbstractAuthService", "GetTokenRequest"] diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/service/get_token_request.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/get_token_request.py new file mode 100644 index 00000000000..96070ef4432 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/get_token_request.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ....core.datetime_utils import serialize_datetime +from ....core.pydantic_utilities import pydantic_v1 + + +class GetTokenRequest(pydantic_v1.BaseModel): + client_id: str + client_secret: str + grant_type: typing.Literal["client_credentials"] + + def json(self, **kwargs: typing.Any) -> str: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().json(**kwargs_with_defaults) + + def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().dict(**kwargs_with_defaults) + + class Config: + extra = pydantic_v1.Extra.forbid + json_encoders = {dt.datetime: serialize_datetime} diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/service/service.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/service.py new file mode 100644 index 00000000000..9aa34aae001 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/service/service.py @@ -0,0 +1,74 @@ +# This file was auto-generated by Fern from our API Definition. + +import abc +import functools +import inspect +import logging +import typing + +import fastapi + +from ....core.abstract_fern_service import AbstractFernService +from ....core.exceptions.fern_http_exception import FernHTTPException +from ....core.route_args import get_route_args +from ..types.token_response import TokenResponse +from .get_token_request import GetTokenRequest + + +class AbstractAuthService(AbstractFernService): + """ + AbstractAuthService is an abstract class containing the methods that you should implement. + + Each method is associated with an API route, which will be registered + with FastAPI when you register your implementation using Fern's register() + function. + """ + + @abc.abstractmethod + def get_token(self, *, body: GetTokenRequest) -> TokenResponse: + ... + + """ + Below are internal methods used by Fern to register your implementation. + You can ignore them. + """ + + @classmethod + def _init_fern(cls, router: fastapi.APIRouter) -> None: + cls.__init_get_token(router=router) + + @classmethod + def __init_get_token(cls, router: fastapi.APIRouter) -> None: + endpoint_function = inspect.signature(cls.get_token) + new_parameters: typing.List[inspect.Parameter] = [] + for index, (parameter_name, parameter) in enumerate(endpoint_function.parameters.items()): + if index == 0: + new_parameters.append(parameter.replace(default=fastapi.Depends(cls))) + elif parameter_name == "body": + new_parameters.append(parameter.replace(default=fastapi.Body(...))) + else: + new_parameters.append(parameter) + setattr(cls.get_token, "__signature__", endpoint_function.replace(parameters=new_parameters)) + + @functools.wraps(cls.get_token) + def wrapper(*args: typing.Any, **kwargs: typing.Any) -> TokenResponse: + try: + return cls.get_token(*args, **kwargs) + except FernHTTPException as e: + logging.getLogger(f"{cls.__module__}.{cls.__name__}").warn( + f"Endpoint 'get_token' unexpectedly threw {e.__class__.__name__}. " + + f"If this was intentional, please add {e.__class__.__name__} to " + + "the endpoint's errors list in your Fern Definition." + ) + raise e + + # this is necessary for FastAPI to find forward-ref'ed type hints. + # https://github.com/tiangolo/fastapi/pull/5077 + wrapper.__globals__.update(cls.get_token.__globals__) + + router.post( + path="//token", + response_model=TokenResponse, + description=AbstractAuthService.get_token.__doc__, + **get_route_args(cls.get_token, default_tag="auth"), + )(wrapper) diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/types/__init__.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/types/__init__.py new file mode 100644 index 00000000000..2ab0052fced --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/types/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .token_response import TokenResponse + +__all__ = ["TokenResponse"] diff --git a/seed/fastapi/oauth-client-credentials-default/resources/auth/types/token_response.py b/seed/fastapi/oauth-client-credentials-default/resources/auth/types/token_response.py new file mode 100644 index 00000000000..643fd071bc7 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/resources/auth/types/token_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ....core.datetime_utils import serialize_datetime +from ....core.pydantic_utilities import pydantic_v1 + + +class TokenResponse(pydantic_v1.BaseModel): + """ + An OAuth token response. + """ + + access_token: str + expires_in: int + + def json(self, **kwargs: typing.Any) -> str: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().json(**kwargs_with_defaults) + + def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().dict(**kwargs_with_defaults) + + class Config: + extra = pydantic_v1.Extra.forbid + json_encoders = {dt.datetime: serialize_datetime} diff --git a/seed/fastapi/oauth-client-credentials-default/security.py b/seed/fastapi/oauth-client-credentials-default/security.py new file mode 100644 index 00000000000..bab014441e1 --- /dev/null +++ b/seed/fastapi/oauth-client-credentials-default/security.py @@ -0,0 +1,11 @@ +# This file was auto-generated by Fern from our API Definition. + +import fastapi + +from .core.security.bearer import BearerToken, HTTPBearer + +ApiAuth = BearerToken + + +def FernAuth(auth: BearerToken = fastapi.Depends(HTTPBearer)) -> BearerToken: + return auth diff --git a/seed/fastapi/oauth-client-credentials-default/snippet-templates.json b/seed/fastapi/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/fastapi/oauth-client-credentials-default/snippet.json b/seed/fastapi/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-fiber/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/go-fiber/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..d4c0a5dcd95 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Compile + run: go build ./... + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Test + run: go test ./... diff --git a/seed/go-fiber/oauth-client-credentials-default/.inputs/config.json b/seed/go-fiber/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..be1f2437d42 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,24 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": null + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/go-fiber/oauth-client-credentials-default/.inputs/ir.json b/seed/go-fiber/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..ee9faca127c --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1145 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": "endpoint_auth.getToken", + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ], + "extra-properties": false + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/go-fiber/oauth-client-credentials-default/.mock/definition/api.yml b/seed/go-fiber/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/go-fiber/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/go-fiber/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/go-fiber/oauth-client-credentials-default/.mock/fern.config.json b/seed/go-fiber/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/go-fiber/oauth-client-credentials-default/.mock/generators.yml b/seed/go-fiber/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/go-fiber/oauth-client-credentials-default/auth.go b/seed/go-fiber/oauth-client-credentials-default/auth.go new file mode 100644 index 00000000000..cc23b9409b6 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/auth.go @@ -0,0 +1,55 @@ +// This file was auto-generated by Fern from our API Definition. + +package oauthclientcredentialsdefault + +import ( + json "encoding/json" + fmt "fmt" + core "github.com/oauth-client-credentials-default/fern/core" +) + +type GetTokenRequest struct { + ClientId string `json:"client_id" url:"-"` + ClientSecret string `json:"client_secret" url:"-"` + grantType string +} + +func (g *GetTokenRequest) GrantType() string { + return g.grantType +} + +func (g *GetTokenRequest) UnmarshalJSON(data []byte) error { + type unmarshaler GetTokenRequest + var body unmarshaler + if err := json.Unmarshal(data, &body); err != nil { + return err + } + *g = GetTokenRequest(body) + g.grantType = "client_credentials" + return nil +} + +func (g *GetTokenRequest) MarshalJSON() ([]byte, error) { + type embed GetTokenRequest + var marshaler = struct { + embed + GrantType string `json:"grant_type"` + }{ + embed: embed(*g), + GrantType: "client_credentials", + } + return json.Marshal(marshaler) +} + +// An OAuth token response. +type TokenResponse struct { + AccessToken string `json:"access_token" url:"access_token"` + ExpiresIn int `json:"expires_in" url:"expires_in"` +} + +func (t *TokenResponse) String() string { + if value, err := core.StringifyJSON(t); err == nil { + return value + } + return fmt.Sprintf("%#v", t) +} diff --git a/seed/go-fiber/oauth-client-credentials-default/core/stringer.go b/seed/go-fiber/oauth-client-credentials-default/core/stringer.go new file mode 100644 index 00000000000..000cf448641 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/core/stringer.go @@ -0,0 +1,13 @@ +package core + +import "encoding/json" + +// StringifyJSON returns a pretty JSON string representation of +// the given value. +func StringifyJSON(value interface{}) (string, error) { + bytes, err := json.MarshalIndent(value, "", " ") + if err != nil { + return "", err + } + return string(bytes), nil +} diff --git a/seed/go-fiber/oauth-client-credentials-default/core/time.go b/seed/go-fiber/oauth-client-credentials-default/core/time.go new file mode 100644 index 00000000000..d009ab30c90 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/core/time.go @@ -0,0 +1,137 @@ +package core + +import ( + "encoding/json" + "time" +) + +const dateFormat = "2006-01-02" + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date (e.g. 2006-01-02). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type Date struct { + t *time.Time +} + +// NewDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewDate(t time.Time) *Date { + return &Date{t: &t} +} + +// NewOptionalDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDate(t *time.Time) *Date { + if t == nil { + return nil + } + return &Date{t: t} +} + +// Time returns the Date's underlying time, if any. If the +// date is nil, the zero value is returned. +func (d *Date) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the Date's underlying time.Time, if any. +func (d *Date) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *Date) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(dateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(dateFormat, raw) + if err != nil { + return err + } + + *d = Date{t: &parsedTime} + return nil +} + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date-time (e.g. 2017-07-21T17:32:28Z). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type DateTime struct { + t *time.Time +} + +// NewDateTime returns a new *DateTime. +func NewDateTime(t time.Time) *DateTime { + return &DateTime{t: &t} +} + +// NewOptionalDateTime returns a new *DateTime. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDateTime(t *time.Time) *DateTime { + if t == nil { + return nil + } + return &DateTime{t: t} +} + +// Time returns the DateTime's underlying time, if any. If the +// date-time is nil, the zero value is returned. +func (d *DateTime) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the DateTime's underlying time.Time, if any. +func (d *DateTime) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *DateTime) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(time.RFC3339)) +} + +func (d *DateTime) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(time.RFC3339, raw) + if err != nil { + return err + } + + *d = DateTime{t: &parsedTime} + return nil +} diff --git a/seed/go-fiber/oauth-client-credentials-default/go.mod b/seed/go-fiber/oauth-client-credentials-default/go.mod new file mode 100644 index 00000000000..a83d69daa30 --- /dev/null +++ b/seed/go-fiber/oauth-client-credentials-default/go.mod @@ -0,0 +1,3 @@ +module github.com/oauth-client-credentials-default/fern + +go 1.13 diff --git a/seed/go-fiber/oauth-client-credentials-default/go.sum b/seed/go-fiber/oauth-client-credentials-default/go.sum new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-fiber/oauth-client-credentials-default/snippet-templates.json b/seed/go-fiber/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-fiber/oauth-client-credentials-default/snippet.json b/seed/go-fiber/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-model/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/go-model/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..d4c0a5dcd95 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Compile + run: go build ./... + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Test + run: go test ./... diff --git a/seed/go-model/oauth-client-credentials-default/.inputs/config.json b/seed/go-model/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..be1f2437d42 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,24 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": null + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/go-model/oauth-client-credentials-default/.inputs/ir.json b/seed/go-model/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..ee9faca127c --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1145 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": "endpoint_auth.getToken", + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ], + "extra-properties": false + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/go-model/oauth-client-credentials-default/.mock/definition/api.yml b/seed/go-model/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/go-model/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/go-model/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/go-model/oauth-client-credentials-default/.mock/fern.config.json b/seed/go-model/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/go-model/oauth-client-credentials-default/.mock/generators.yml b/seed/go-model/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/go-model/oauth-client-credentials-default/auth.go b/seed/go-model/oauth-client-credentials-default/auth.go new file mode 100644 index 00000000000..2ede3ee834b --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/auth.go @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +package oauthclientcredentialsdefault + +import ( + fmt "fmt" + core "github.com/oauth-client-credentials-default/fern/core" +) + +// An OAuth token response. +type TokenResponse struct { + AccessToken string `json:"access_token" url:"access_token"` + ExpiresIn int `json:"expires_in" url:"expires_in"` +} + +func (t *TokenResponse) String() string { + if value, err := core.StringifyJSON(t); err == nil { + return value + } + return fmt.Sprintf("%#v", t) +} diff --git a/seed/go-model/oauth-client-credentials-default/core/stringer.go b/seed/go-model/oauth-client-credentials-default/core/stringer.go new file mode 100644 index 00000000000..000cf448641 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/core/stringer.go @@ -0,0 +1,13 @@ +package core + +import "encoding/json" + +// StringifyJSON returns a pretty JSON string representation of +// the given value. +func StringifyJSON(value interface{}) (string, error) { + bytes, err := json.MarshalIndent(value, "", " ") + if err != nil { + return "", err + } + return string(bytes), nil +} diff --git a/seed/go-model/oauth-client-credentials-default/core/time.go b/seed/go-model/oauth-client-credentials-default/core/time.go new file mode 100644 index 00000000000..d009ab30c90 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/core/time.go @@ -0,0 +1,137 @@ +package core + +import ( + "encoding/json" + "time" +) + +const dateFormat = "2006-01-02" + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date (e.g. 2006-01-02). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type Date struct { + t *time.Time +} + +// NewDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewDate(t time.Time) *Date { + return &Date{t: &t} +} + +// NewOptionalDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDate(t *time.Time) *Date { + if t == nil { + return nil + } + return &Date{t: t} +} + +// Time returns the Date's underlying time, if any. If the +// date is nil, the zero value is returned. +func (d *Date) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the Date's underlying time.Time, if any. +func (d *Date) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *Date) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(dateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(dateFormat, raw) + if err != nil { + return err + } + + *d = Date{t: &parsedTime} + return nil +} + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date-time (e.g. 2017-07-21T17:32:28Z). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type DateTime struct { + t *time.Time +} + +// NewDateTime returns a new *DateTime. +func NewDateTime(t time.Time) *DateTime { + return &DateTime{t: &t} +} + +// NewOptionalDateTime returns a new *DateTime. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDateTime(t *time.Time) *DateTime { + if t == nil { + return nil + } + return &DateTime{t: t} +} + +// Time returns the DateTime's underlying time, if any. If the +// date-time is nil, the zero value is returned. +func (d *DateTime) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the DateTime's underlying time.Time, if any. +func (d *DateTime) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *DateTime) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(time.RFC3339)) +} + +func (d *DateTime) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(time.RFC3339, raw) + if err != nil { + return err + } + + *d = DateTime{t: &parsedTime} + return nil +} diff --git a/seed/go-model/oauth-client-credentials-default/go.mod b/seed/go-model/oauth-client-credentials-default/go.mod new file mode 100644 index 00000000000..a83d69daa30 --- /dev/null +++ b/seed/go-model/oauth-client-credentials-default/go.mod @@ -0,0 +1,3 @@ +module github.com/oauth-client-credentials-default/fern + +go 1.13 diff --git a/seed/go-model/oauth-client-credentials-default/go.sum b/seed/go-model/oauth-client-credentials-default/go.sum new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-model/oauth-client-credentials-default/snippet-templates.json b/seed/go-model/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-model/oauth-client-credentials-default/snippet.json b/seed/go-model/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-sdk/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/go-sdk/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..d4c0a5dcd95 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Compile + run: go build ./... + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v4 + + - name: Test + run: go test ./... diff --git a/seed/go-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/go-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..be1f2437d42 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,24 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": null + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/go-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/go-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..ee9faca127c --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1145 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": "endpoint_auth.getToken", + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ], + "extra-properties": false + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/go-sdk/oauth-client-credentials-default/.mock/definition/api.yml b/seed/go-sdk/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/go-sdk/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/go-sdk/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/go-sdk/oauth-client-credentials-default/.mock/fern.config.json b/seed/go-sdk/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/go-sdk/oauth-client-credentials-default/.mock/generators.yml b/seed/go-sdk/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/go-sdk/oauth-client-credentials-default/auth.go b/seed/go-sdk/oauth-client-credentials-default/auth.go new file mode 100644 index 00000000000..0991af86b5a --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/auth.go @@ -0,0 +1,73 @@ +// This file was auto-generated by Fern from our API Definition. + +package oauthclientcredentialsdefault + +import ( + json "encoding/json" + fmt "fmt" + core "github.com/oauth-client-credentials-default/fern/core" +) + +type GetTokenRequest struct { + ClientId string `json:"client_id" url:"-"` + ClientSecret string `json:"client_secret" url:"-"` + grantType string +} + +func (g *GetTokenRequest) GrantType() string { + return g.grantType +} + +func (g *GetTokenRequest) UnmarshalJSON(data []byte) error { + type unmarshaler GetTokenRequest + var body unmarshaler + if err := json.Unmarshal(data, &body); err != nil { + return err + } + *g = GetTokenRequest(body) + g.grantType = "client_credentials" + return nil +} + +func (g *GetTokenRequest) MarshalJSON() ([]byte, error) { + type embed GetTokenRequest + var marshaler = struct { + embed + GrantType string `json:"grant_type"` + }{ + embed: embed(*g), + GrantType: "client_credentials", + } + return json.Marshal(marshaler) +} + +// An OAuth token response. +type TokenResponse struct { + AccessToken string `json:"access_token" url:"access_token"` + ExpiresIn int `json:"expires_in" url:"expires_in"` + + _rawJSON json.RawMessage +} + +func (t *TokenResponse) UnmarshalJSON(data []byte) error { + type unmarshaler TokenResponse + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *t = TokenResponse(value) + t._rawJSON = json.RawMessage(data) + return nil +} + +func (t *TokenResponse) String() string { + if len(t._rawJSON) > 0 { + if value, err := core.StringifyJSON(t._rawJSON); err == nil { + return value + } + } + if value, err := core.StringifyJSON(t); err == nil { + return value + } + return fmt.Sprintf("%#v", t) +} diff --git a/seed/go-sdk/oauth-client-credentials-default/auth/client.go b/seed/go-sdk/oauth-client-credentials-default/auth/client.go new file mode 100644 index 00000000000..29714ed9664 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/auth/client.go @@ -0,0 +1,67 @@ +// This file was auto-generated by Fern from our API Definition. + +package auth + +import ( + context "context" + fern "github.com/oauth-client-credentials-default/fern" + core "github.com/oauth-client-credentials-default/fern/core" + option "github.com/oauth-client-credentials-default/fern/option" + http "net/http" +) + +type Client struct { + baseURL string + caller *core.Caller + header http.Header +} + +func NewClient(opts ...option.RequestOption) *Client { + options := core.NewRequestOptions(opts...) + return &Client{ + baseURL: options.BaseURL, + caller: core.NewCaller( + &core.CallerParams{ + Client: options.HTTPClient, + MaxAttempts: options.MaxAttempts, + }, + ), + header: options.ToHeader(), + } +} + +func (c *Client) GetToken( + ctx context.Context, + request *fern.GetTokenRequest, + opts ...option.RequestOption, +) (*fern.TokenResponse, error) { + options := core.NewRequestOptions(opts...) + + baseURL := "" + if c.baseURL != "" { + baseURL = c.baseURL + } + if options.BaseURL != "" { + baseURL = options.BaseURL + } + endpointURL := baseURL + "/token" + + headers := core.MergeHeaders(c.header.Clone(), options.ToHeader()) + + var response *fern.TokenResponse + if err := c.caller.Call( + ctx, + &core.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + MaxAttempts: options.MaxAttempts, + Headers: headers, + Client: options.HTTPClient, + Request: request, + Response: &response, + }, + ); err != nil { + return nil, err + } + return response, nil +} diff --git a/seed/go-sdk/oauth-client-credentials-default/client/client.go b/seed/go-sdk/oauth-client-credentials-default/client/client.go new file mode 100644 index 00000000000..730f6d70ae9 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/client/client.go @@ -0,0 +1,33 @@ +// This file was auto-generated by Fern from our API Definition. + +package client + +import ( + auth "github.com/oauth-client-credentials-default/fern/auth" + core "github.com/oauth-client-credentials-default/fern/core" + option "github.com/oauth-client-credentials-default/fern/option" + http "net/http" +) + +type Client struct { + baseURL string + caller *core.Caller + header http.Header + + Auth *auth.Client +} + +func NewClient(opts ...option.RequestOption) *Client { + options := core.NewRequestOptions(opts...) + return &Client{ + baseURL: options.BaseURL, + caller: core.NewCaller( + &core.CallerParams{ + Client: options.HTTPClient, + MaxAttempts: options.MaxAttempts, + }, + ), + header: options.ToHeader(), + Auth: auth.NewClient(opts...), + } +} diff --git a/seed/go-sdk/oauth-client-credentials-default/client/client_test.go b/seed/go-sdk/oauth-client-credentials-default/client/client_test.go new file mode 100644 index 00000000000..827e6bd4481 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/client/client_test.go @@ -0,0 +1,45 @@ +// This file was auto-generated by Fern from our API Definition. + +package client + +import ( + option "github.com/oauth-client-credentials-default/fern/option" + assert "github.com/stretchr/testify/assert" + http "net/http" + testing "testing" + time "time" +) + +func TestNewClient(t *testing.T) { + t.Run("default", func(t *testing.T) { + c := NewClient() + assert.Empty(t, c.baseURL) + }) + + t.Run("base url", func(t *testing.T) { + c := NewClient( + option.WithBaseURL("test.co"), + ) + assert.Equal(t, "test.co", c.baseURL) + }) + + t.Run("http client", func(t *testing.T) { + httpClient := &http.Client{ + Timeout: 5 * time.Second, + } + c := NewClient( + option.WithHTTPClient(httpClient), + ) + assert.Empty(t, c.baseURL) + }) + + t.Run("http header", func(t *testing.T) { + header := make(http.Header) + header.Set("X-API-Tenancy", "test") + c := NewClient( + option.WithHTTPHeader(header), + ) + assert.Empty(t, c.baseURL) + assert.Equal(t, "test", c.header.Get("X-API-Tenancy")) + }) +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/core.go b/seed/go-sdk/oauth-client-credentials-default/core/core.go new file mode 100644 index 00000000000..3e28f90853c --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/core.go @@ -0,0 +1,280 @@ +package core + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" +) + +const ( + // contentType specifies the JSON Content-Type header value. + contentType = "application/json" + contentTypeHeader = "Content-Type" +) + +// HTTPClient is an interface for a subset of the *http.Client. +type HTTPClient interface { + Do(*http.Request) (*http.Response, error) +} + +// EncodeURL encodes the given arguments into the URL, escaping +// values as needed. +func EncodeURL(urlFormat string, args ...interface{}) string { + escapedArgs := make([]interface{}, 0, len(args)) + for _, arg := range args { + escapedArgs = append(escapedArgs, url.PathEscape(fmt.Sprintf("%v", arg))) + } + return fmt.Sprintf(urlFormat, escapedArgs...) +} + +// MergeHeaders merges the given headers together, where the right +// takes precedence over the left. +func MergeHeaders(left, right http.Header) http.Header { + for key, values := range right { + if len(values) > 1 { + left[key] = values + continue + } + if value := right.Get(key); value != "" { + left.Set(key, value) + } + } + return left +} + +// WriteMultipartJSON writes the given value as a JSON part. +// This is used to serialize non-primitive multipart properties +// (i.e. lists, objects, etc). +func WriteMultipartJSON(writer *multipart.Writer, field string, value interface{}) error { + bytes, err := json.Marshal(value) + if err != nil { + return err + } + return writer.WriteField(field, string(bytes)) +} + +// APIError is a lightweight wrapper around the standard error +// interface that preserves the status code from the RPC, if any. +type APIError struct { + err error + + StatusCode int `json:"-"` +} + +// NewAPIError constructs a new API error. +func NewAPIError(statusCode int, err error) *APIError { + return &APIError{ + err: err, + StatusCode: statusCode, + } +} + +// Unwrap returns the underlying error. This also makes the error compatible +// with errors.As and errors.Is. +func (a *APIError) Unwrap() error { + if a == nil { + return nil + } + return a.err +} + +// Error returns the API error's message. +func (a *APIError) Error() string { + if a == nil || (a.err == nil && a.StatusCode == 0) { + return "" + } + if a.err == nil { + return fmt.Sprintf("%d", a.StatusCode) + } + if a.StatusCode == 0 { + return a.err.Error() + } + return fmt.Sprintf("%d: %s", a.StatusCode, a.err.Error()) +} + +// ErrorDecoder decodes *http.Response errors and returns a +// typed API error (e.g. *APIError). +type ErrorDecoder func(statusCode int, body io.Reader) error + +// Caller calls APIs and deserializes their response, if any. +type Caller struct { + client HTTPClient + retrier *Retrier +} + +// CallerParams represents the parameters used to constrcut a new *Caller. +type CallerParams struct { + Client HTTPClient + MaxAttempts uint +} + +// NewCaller returns a new *Caller backed by the given parameters. +func NewCaller(params *CallerParams) *Caller { + var httpClient HTTPClient = http.DefaultClient + if params.Client != nil { + httpClient = params.Client + } + var retryOptions []RetryOption + if params.MaxAttempts > 0 { + retryOptions = append(retryOptions, WithMaxAttempts(params.MaxAttempts)) + } + return &Caller{ + client: httpClient, + retrier: NewRetrier(retryOptions...), + } +} + +// CallParams represents the parameters used to issue an API call. +type CallParams struct { + URL string + Method string + MaxAttempts uint + Headers http.Header + Client HTTPClient + Request interface{} + Response interface{} + ResponseIsOptional bool + ErrorDecoder ErrorDecoder +} + +// Call issues an API call according to the given call parameters. +func (c *Caller) Call(ctx context.Context, params *CallParams) error { + req, err := newRequest(ctx, params.URL, params.Method, params.Headers, params.Request) + if err != nil { + return err + } + + // If the call has been cancelled, don't issue the request. + if err := ctx.Err(); err != nil { + return err + } + + client := c.client + if params.Client != nil { + // Use the HTTP client scoped to the request. + client = params.Client + } + + var retryOptions []RetryOption + if params.MaxAttempts > 0 { + retryOptions = append(retryOptions, WithMaxAttempts(params.MaxAttempts)) + } + + resp, err := c.retrier.Run( + client.Do, + req, + params.ErrorDecoder, + retryOptions..., + ) + if err != nil { + return err + } + + // Close the response body after we're done. + defer resp.Body.Close() + + // Check if the call was cancelled before we return the error + // associated with the call and/or unmarshal the response data. + if err := ctx.Err(); err != nil { + return err + } + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return decodeError(resp, params.ErrorDecoder) + } + + // Mutate the response parameter in-place. + if params.Response != nil { + if writer, ok := params.Response.(io.Writer); ok { + _, err = io.Copy(writer, resp.Body) + } else { + err = json.NewDecoder(resp.Body).Decode(params.Response) + } + if err != nil { + if err == io.EOF { + if params.ResponseIsOptional { + // The response is optional, so we should ignore the + // io.EOF error + return nil + } + return fmt.Errorf("expected a %T response, but the server responded with nothing", params.Response) + } + return err + } + } + + return nil +} + +// newRequest returns a new *http.Request with all of the fields +// required to issue the call. +func newRequest( + ctx context.Context, + url string, + method string, + endpointHeaders http.Header, + request interface{}, +) (*http.Request, error) { + requestBody, err := newRequestBody(request) + if err != nil { + return nil, err + } + req, err := http.NewRequestWithContext(ctx, method, url, requestBody) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + req.Header.Set(contentTypeHeader, contentType) + for name, values := range endpointHeaders { + req.Header[name] = values + } + return req, nil +} + +// newRequestBody returns a new io.Reader that represents the HTTP request body. +func newRequestBody(request interface{}) (io.Reader, error) { + var requestBody io.Reader + if request != nil { + if body, ok := request.(io.Reader); ok { + requestBody = body + } else { + requestBytes, err := json.Marshal(request) + if err != nil { + return nil, err + } + requestBody = bytes.NewReader(requestBytes) + } + } + return requestBody, nil +} + +// decodeError decodes the error from the given HTTP response. Note that +// it's the caller's responsibility to close the response body. +func decodeError(response *http.Response, errorDecoder ErrorDecoder) error { + if errorDecoder != nil { + // This endpoint has custom errors, so we'll + // attempt to unmarshal the error into a structured + // type based on the status code. + return errorDecoder(response.StatusCode, response.Body) + } + // This endpoint doesn't have any custom error + // types, so we just read the body as-is, and + // put it into a normal error. + bytes, err := io.ReadAll(response.Body) + if err != nil && err != io.EOF { + return err + } + if err == io.EOF { + // The error didn't have a response body, + // so all we can do is return an error + // with the status code. + return NewAPIError(response.StatusCode, nil) + } + return NewAPIError(response.StatusCode, errors.New(string(bytes))) +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/core_test.go b/seed/go-sdk/oauth-client-credentials-default/core/core_test.go new file mode 100644 index 00000000000..f476f9ee383 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/core_test.go @@ -0,0 +1,284 @@ +package core + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestCase represents a single test case. +type TestCase struct { + description string + + // Server-side assertions. + giveMethod string + giveResponseIsOptional bool + giveHeader http.Header + giveErrorDecoder ErrorDecoder + giveRequest *Request + + // Client-side assertions. + wantResponse *Response + wantError error +} + +// Request a simple request body. +type Request struct { + Id string `json:"id"` +} + +// Response a simple response body. +type Response struct { + Id string `json:"id"` +} + +// NotFoundError represents a 404. +type NotFoundError struct { + *APIError + + Message string `json:"message"` +} + +func TestCall(t *testing.T) { + tests := []*TestCase{ + { + description: "GET success", + giveMethod: http.MethodGet, + giveHeader: http.Header{ + "X-API-Status": []string{"success"}, + }, + giveRequest: &Request{ + Id: "123", + }, + wantResponse: &Response{ + Id: "123", + }, + }, + { + description: "GET not found", + giveMethod: http.MethodGet, + giveHeader: http.Header{ + "X-API-Status": []string{"fail"}, + }, + giveRequest: &Request{ + Id: strconv.Itoa(http.StatusNotFound), + }, + giveErrorDecoder: newTestErrorDecoder(t), + wantError: &NotFoundError{ + APIError: NewAPIError( + http.StatusNotFound, + errors.New(`{"message":"ID \"404\" not found"}`), + ), + }, + }, + { + description: "POST optional response", + giveMethod: http.MethodPost, + giveHeader: http.Header{ + "X-API-Status": []string{"success"}, + }, + giveRequest: &Request{ + Id: "123", + }, + giveResponseIsOptional: true, + }, + { + description: "POST API error", + giveMethod: http.MethodPost, + giveHeader: http.Header{ + "X-API-Status": []string{"fail"}, + }, + giveRequest: &Request{ + Id: strconv.Itoa(http.StatusInternalServerError), + }, + wantError: NewAPIError( + http.StatusInternalServerError, + errors.New("failed to process request"), + ), + }, + } + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + var ( + server = newTestServer(t, test) + client = server.Client() + ) + caller := NewCaller( + &CallerParams{ + Client: client, + }, + ) + var response *Response + err := caller.Call( + context.Background(), + &CallParams{ + URL: server.URL, + Method: test.giveMethod, + Headers: test.giveHeader, + Request: test.giveRequest, + Response: &response, + ResponseIsOptional: test.giveResponseIsOptional, + ErrorDecoder: test.giveErrorDecoder, + }, + ) + if test.wantError != nil { + assert.EqualError(t, err, test.wantError.Error()) + return + } + require.NoError(t, err) + assert.Equal(t, test.wantResponse, response) + }) + } +} + +func TestMergeHeaders(t *testing.T) { + t.Run("both empty", func(t *testing.T) { + merged := MergeHeaders(make(http.Header), make(http.Header)) + assert.Empty(t, merged) + }) + + t.Run("empty left", func(t *testing.T) { + left := make(http.Header) + + right := make(http.Header) + right.Set("X-API-Version", "0.0.1") + + merged := MergeHeaders(left, right) + assert.Equal(t, "0.0.1", merged.Get("X-API-Version")) + }) + + t.Run("empty right", func(t *testing.T) { + left := make(http.Header) + left.Set("X-API-Version", "0.0.1") + + right := make(http.Header) + + merged := MergeHeaders(left, right) + assert.Equal(t, "0.0.1", merged.Get("X-API-Version")) + }) + + t.Run("single value override", func(t *testing.T) { + left := make(http.Header) + left.Set("X-API-Version", "0.0.0") + + right := make(http.Header) + right.Set("X-API-Version", "0.0.1") + + merged := MergeHeaders(left, right) + assert.Equal(t, []string{"0.0.1"}, merged.Values("X-API-Version")) + }) + + t.Run("multiple value override", func(t *testing.T) { + left := make(http.Header) + left.Set("X-API-Versions", "0.0.0") + + right := make(http.Header) + right.Add("X-API-Versions", "0.0.1") + right.Add("X-API-Versions", "0.0.2") + + merged := MergeHeaders(left, right) + assert.Equal(t, []string{"0.0.1", "0.0.2"}, merged.Values("X-API-Versions")) + }) + + t.Run("disjoint merge", func(t *testing.T) { + left := make(http.Header) + left.Set("X-API-Tenancy", "test") + + right := make(http.Header) + right.Set("X-API-Version", "0.0.1") + + merged := MergeHeaders(left, right) + assert.Equal(t, []string{"test"}, merged.Values("X-API-Tenancy")) + assert.Equal(t, []string{"0.0.1"}, merged.Values("X-API-Version")) + }) +} + +// newTestServer returns a new *httptest.Server configured with the +// given test parameters. +func newTestServer(t *testing.T, tc *TestCase) *httptest.Server { + return httptest.NewServer( + http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, tc.giveMethod, r.Method) + assert.Equal(t, contentType, r.Header.Get(contentTypeHeader)) + for header, value := range tc.giveHeader { + assert.Equal(t, value, r.Header.Values(header)) + } + + bytes, err := io.ReadAll(r.Body) + require.NoError(t, err) + + request := new(Request) + require.NoError(t, json.Unmarshal(bytes, request)) + + switch request.Id { + case strconv.Itoa(http.StatusNotFound): + notFoundError := &NotFoundError{ + APIError: &APIError{ + StatusCode: http.StatusNotFound, + }, + Message: fmt.Sprintf("ID %q not found", request.Id), + } + bytes, err = json.Marshal(notFoundError) + require.NoError(t, err) + + w.WriteHeader(http.StatusNotFound) + _, err = w.Write(bytes) + require.NoError(t, err) + return + + case strconv.Itoa(http.StatusInternalServerError): + w.WriteHeader(http.StatusInternalServerError) + _, err = w.Write([]byte("failed to process request")) + require.NoError(t, err) + return + } + + if tc.giveResponseIsOptional { + w.WriteHeader(http.StatusOK) + return + } + + response := &Response{ + Id: request.Id, + } + bytes, err = json.Marshal(response) + require.NoError(t, err) + + _, err = w.Write(bytes) + require.NoError(t, err) + }, + ), + ) +} + +// newTestErrorDecoder returns an error decoder suitable for tests. +func newTestErrorDecoder(t *testing.T) func(int, io.Reader) error { + return func(statusCode int, body io.Reader) error { + raw, err := io.ReadAll(body) + require.NoError(t, err) + + var ( + apiError = NewAPIError(statusCode, errors.New(string(raw))) + decoder = json.NewDecoder(bytes.NewReader(raw)) + ) + if statusCode == http.StatusNotFound { + value := new(NotFoundError) + value.APIError = apiError + require.NoError(t, decoder.Decode(value)) + + return value + } + return apiError + } +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/query.go b/seed/go-sdk/oauth-client-credentials-default/core/query.go new file mode 100644 index 00000000000..3febdc7974d --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/query.go @@ -0,0 +1,219 @@ +package core + +import ( + "encoding/base64" + "fmt" + "net/url" + "reflect" + "strings" + "time" + + "github.com/google/uuid" +) + +var ( + bytesType = reflect.TypeOf([]byte{}) + queryEncoderType = reflect.TypeOf(new(QueryEncoder)).Elem() + timeType = reflect.TypeOf(time.Time{}) + uuidType = reflect.TypeOf(uuid.UUID{}) +) + +// QueryEncoder is an interface implemented by any type that wishes to encode +// itself into URL values in a non-standard way. +type QueryEncoder interface { + EncodeQueryValues(key string, v *url.Values) error +} + +// QueryValues encodes url.Values from request objects. +// +// Note: This type is inspired by Google's query encoding library, but +// supports far less customization and is tailored to fit this SDK's use case. +// +// Ref: https://github.com/google/go-querystring +func QueryValues(v interface{}) (url.Values, error) { + values := make(url.Values) + val := reflect.ValueOf(v) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return values, nil + } + val = val.Elem() + } + + if v == nil { + return values, nil + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind()) + } + + err := reflectValue(values, val, "") + return values, err +} + +// reflectValue populates the values parameter from the struct fields in val. +// Embedded structs are followed recursively (using the rules defined in the +// Values function documentation) breadth-first. +func reflectValue(values url.Values, val reflect.Value, scope string) error { + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { + // Skip unexported fields. + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get("url") + if tag == "" || tag == "-" { + continue + } + + name, opts := parseTag(tag) + if name == "" { + name = sf.Name + } + + if scope != "" { + name = scope + "[" + name + "]" + } + + if opts.Contains("omitempty") && isEmptyValue(sv) { + continue + } + + if sv.Type().Implements(queryEncoderType) { + // If sv is a nil pointer and the custom encoder is defined on a non-pointer + // method receiver, set sv to the zero value of the underlying type + if !reflect.Indirect(sv).IsValid() && sv.Type().Elem().Implements(queryEncoderType) { + sv = reflect.New(sv.Type().Elem()) + } + + m := sv.Interface().(QueryEncoder) + if err := m.EncodeQueryValues(name, &values); err != nil { + return err + } + continue + } + + // Recursively dereference pointers, but stop at nil pointers. + for sv.Kind() == reflect.Ptr { + if sv.IsNil() { + break + } + sv = sv.Elem() + } + + if sv.Type() == uuidType || sv.Type() == bytesType || sv.Type() == timeType { + values.Add(name, valueString(sv, opts, sf)) + continue + } + + if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { + if sv.Len() == 0 { + // Skip if slice or array is empty. + continue + } + for i := 0; i < sv.Len(); i++ { + values.Add(name, valueString(sv.Index(i), opts, sf)) + } + continue + } + + if sv.Kind() == reflect.Struct { + if err := reflectValue(values, sv, name); err != nil { + return err + } + continue + } + + values.Add(name, valueString(sv, opts, sf)) + } + + return nil +} + +// valueString returns the string representation of a value. +func valueString(v reflect.Value, opts tagOptions, sf reflect.StructField) string { + for v.Kind() == reflect.Ptr { + if v.IsNil() { + return "" + } + v = v.Elem() + } + + if v.Type() == timeType { + t := v.Interface().(time.Time) + if format := sf.Tag.Get("format"); format == "date" { + return t.Format("2006-01-02") + } + return t.Format(time.RFC3339) + } + + if v.Type() == uuidType { + u := v.Interface().(uuid.UUID) + return u.String() + } + + if v.Type() == bytesType { + b := v.Interface().([]byte) + return base64.StdEncoding.EncodeToString(b) + } + + return fmt.Sprint(v.Interface()) +} + +// isEmptyValue checks if a value should be considered empty for the purposes +// of omitting fields with the "omitempty" option. +func isEmptyValue(v reflect.Value) bool { + type zeroable interface { + IsZero() bool + } + + if !v.IsZero() { + if z, ok := v.Interface().(zeroable); ok { + return z.IsZero() + } + } + + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Invalid, reflect.Complex64, reflect.Complex128, reflect.Chan, reflect.Func, reflect.Struct, reflect.UnsafePointer: + return false + } + + return false +} + +// tagOptions is the string following a comma in a struct field's "url" tag, or +// the empty string. It does not include the leading comma. +type tagOptions []string + +// parseTag splits a struct field's url tag into its name and comma-separated +// options. +func parseTag(tag string) (string, tagOptions) { + s := strings.Split(tag, ",") + return s[0], s[1:] +} + +// Contains checks whether the tagOptions contains the specified option. +func (o tagOptions) Contains(option string) bool { + for _, s := range o { + if s == option { + return true + } + } + return false +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/query_test.go b/seed/go-sdk/oauth-client-credentials-default/core/query_test.go new file mode 100644 index 00000000000..aad030a370f --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/query_test.go @@ -0,0 +1,160 @@ +package core + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestQueryValues(t *testing.T) { + t.Run("empty optional", func(t *testing.T) { + type nested struct { + Value *string `json:"value,omitempty" url:"value,omitempty"` + } + type example struct { + Nested *nested `json:"nested,omitempty" url:"nested,omitempty"` + } + + values, err := QueryValues(&example{}) + require.NoError(t, err) + assert.Empty(t, values) + }) + + t.Run("empty required", func(t *testing.T) { + type nested struct { + Value *string `json:"value,omitempty" url:"value,omitempty"` + } + type example struct { + Required string `json:"required" url:"required"` + Nested *nested `json:"nested,omitempty" url:"nested,omitempty"` + } + + values, err := QueryValues(&example{}) + require.NoError(t, err) + assert.Equal(t, "required=", values.Encode()) + }) + + t.Run("allow multiple", func(t *testing.T) { + type example struct { + Values []string `json:"values" url:"values"` + } + + values, err := QueryValues( + &example{ + Values: []string{"foo", "bar", "baz"}, + }, + ) + require.NoError(t, err) + assert.Equal(t, "values=foo&values=bar&values=baz", values.Encode()) + }) + + t.Run("nested object", func(t *testing.T) { + type nested struct { + Value *string `json:"value,omitempty" url:"value,omitempty"` + } + type example struct { + Required string `json:"required" url:"required"` + Nested *nested `json:"nested,omitempty" url:"nested,omitempty"` + } + + nestedValue := "nestedValue" + values, err := QueryValues( + &example{ + Required: "requiredValue", + Nested: &nested{ + Value: &nestedValue, + }, + }, + ) + require.NoError(t, err) + assert.Equal(t, "nested%5Bvalue%5D=nestedValue&required=requiredValue", values.Encode()) + }) + + t.Run("url unspecified", func(t *testing.T) { + type example struct { + Required string `json:"required" url:"required"` + NotFound string `json:"notFound"` + } + + values, err := QueryValues( + &example{ + Required: "requiredValue", + NotFound: "notFound", + }, + ) + require.NoError(t, err) + assert.Equal(t, "required=requiredValue", values.Encode()) + }) + + t.Run("url ignored", func(t *testing.T) { + type example struct { + Required string `json:"required" url:"required"` + NotFound string `json:"notFound" url:"-"` + } + + values, err := QueryValues( + &example{ + Required: "requiredValue", + NotFound: "notFound", + }, + ) + require.NoError(t, err) + assert.Equal(t, "required=requiredValue", values.Encode()) + }) + + t.Run("datetime", func(t *testing.T) { + type example struct { + DateTime time.Time `json:"dateTime" url:"dateTime"` + } + + values, err := QueryValues( + &example{ + DateTime: time.Date(1994, 3, 16, 12, 34, 56, 0, time.UTC), + }, + ) + require.NoError(t, err) + assert.Equal(t, "dateTime=1994-03-16T12%3A34%3A56Z", values.Encode()) + }) + + t.Run("date", func(t *testing.T) { + type example struct { + Date time.Time `json:"date" url:"date" format:"date"` + } + + values, err := QueryValues( + &example{ + Date: time.Date(1994, 3, 16, 12, 34, 56, 0, time.UTC), + }, + ) + require.NoError(t, err) + assert.Equal(t, "date=1994-03-16", values.Encode()) + }) + + t.Run("optional time", func(t *testing.T) { + type example struct { + Date *time.Time `json:"date,omitempty" url:"date,omitempty" format:"date"` + } + + values, err := QueryValues( + &example{}, + ) + require.NoError(t, err) + assert.Empty(t, values.Encode()) + }) + + t.Run("omitempty with non-pointer zero value", func(t *testing.T) { + type enum string + + type example struct { + Enum enum `json:"enum,omitempty" url:"enum,omitempty"` + } + + values, err := QueryValues( + &example{}, + ) + require.NoError(t, err) + assert.Empty(t, values.Encode()) + }) +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/request_option.go b/seed/go-sdk/oauth-client-credentials-default/core/request_option.go new file mode 100644 index 00000000000..bd6615e12a7 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/request_option.go @@ -0,0 +1,88 @@ +// This file was auto-generated by Fern from our API Definition. + +package core + +import ( + http "net/http" +) + +// RequestOption adapts the behavior of the client or an individual request. +type RequestOption interface { + applyRequestOptions(*RequestOptions) +} + +// RequestOptions defines all of the possible request options. +// +// This type is primarily used by the generated code and is not meant +// to be used directly; use the option package instead. +type RequestOptions struct { + BaseURL string + HTTPClient HTTPClient + HTTPHeader http.Header + MaxAttempts uint +} + +// NewRequestOptions returns a new *RequestOptions value. +// +// This function is primarily used by the generated code and is not meant +// to be used directly; use RequestOption instead. +func NewRequestOptions(opts ...RequestOption) *RequestOptions { + options := &RequestOptions{ + HTTPHeader: make(http.Header), + } + for _, opt := range opts { + opt.applyRequestOptions(options) + } + return options +} + +// ToHeader maps the configured request options into a http.Header used +// for the request(s). +func (r *RequestOptions) ToHeader() http.Header { + header := r.cloneHeader() + return header +} + +func (r *RequestOptions) cloneHeader() http.Header { + headers := r.HTTPHeader.Clone() + headers.Set("X-Fern-Language", "Go") + headers.Set("X-Fern-SDK-Name", "github.com/oauth-client-credentials-default/fern") + headers.Set("X-Fern-SDK-Version", "0.0.1") + return headers +} + +// BaseURLOption implements the RequestOption interface. +type BaseURLOption struct { + BaseURL string +} + +func (b *BaseURLOption) applyRequestOptions(opts *RequestOptions) { + opts.BaseURL = b.BaseURL +} + +// HTTPClientOption implements the RequestOption interface. +type HTTPClientOption struct { + HTTPClient HTTPClient +} + +func (h *HTTPClientOption) applyRequestOptions(opts *RequestOptions) { + opts.HTTPClient = h.HTTPClient +} + +// HTTPHeaderOption implements the RequestOption interface. +type HTTPHeaderOption struct { + HTTPHeader http.Header +} + +func (h *HTTPHeaderOption) applyRequestOptions(opts *RequestOptions) { + opts.HTTPHeader = h.HTTPHeader +} + +// MaxAttemptsOption implements the RequestOption interface. +type MaxAttemptsOption struct { + MaxAttempts uint +} + +func (m *MaxAttemptsOption) applyRequestOptions(opts *RequestOptions) { + opts.MaxAttempts = m.MaxAttempts +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/retrier.go b/seed/go-sdk/oauth-client-credentials-default/core/retrier.go new file mode 100644 index 00000000000..ea24916b786 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/retrier.go @@ -0,0 +1,166 @@ +package core + +import ( + "crypto/rand" + "math/big" + "net/http" + "time" +) + +const ( + defaultRetryAttempts = 2 + minRetryDelay = 500 * time.Millisecond + maxRetryDelay = 5000 * time.Millisecond +) + +// RetryOption adapts the behavior the *Retrier. +type RetryOption func(*retryOptions) + +// RetryFunc is a retriable HTTP function call (i.e. *http.Client.Do). +type RetryFunc func(*http.Request) (*http.Response, error) + +// WithMaxAttempts configures the maximum number of attempts +// of the *Retrier. +func WithMaxAttempts(attempts uint) RetryOption { + return func(opts *retryOptions) { + opts.attempts = attempts + } +} + +// Retrier retries failed requests a configurable number of times with an +// exponential back-off between each retry. +type Retrier struct { + attempts uint +} + +// NewRetrier constructs a new *Retrier with the given options, if any. +func NewRetrier(opts ...RetryOption) *Retrier { + options := new(retryOptions) + for _, opt := range opts { + opt(options) + } + attempts := uint(defaultRetryAttempts) + if options.attempts > 0 { + attempts = options.attempts + } + return &Retrier{ + attempts: attempts, + } +} + +// Run issues the request and, upon failure, retries the request if possible. +// +// The request will be retried as long as the request is deemed retriable and the +// number of retry attempts has not grown larger than the configured retry limit. +func (r *Retrier) Run( + fn RetryFunc, + request *http.Request, + errorDecoder ErrorDecoder, + opts ...RetryOption, +) (*http.Response, error) { + options := new(retryOptions) + for _, opt := range opts { + opt(options) + } + maxRetryAttempts := r.attempts + if options.attempts > 0 { + maxRetryAttempts = options.attempts + } + var ( + retryAttempt uint + previousError error + ) + return r.run( + fn, + request, + errorDecoder, + maxRetryAttempts, + retryAttempt, + previousError, + ) +} + +func (r *Retrier) run( + fn RetryFunc, + request *http.Request, + errorDecoder ErrorDecoder, + maxRetryAttempts uint, + retryAttempt uint, + previousError error, +) (*http.Response, error) { + if retryAttempt >= maxRetryAttempts { + return nil, previousError + } + + // If the call has been cancelled, don't issue the request. + if err := request.Context().Err(); err != nil { + return nil, err + } + + response, err := fn(request) + if err != nil { + return nil, err + } + + if r.shouldRetry(response) { + defer response.Body.Close() + + delay, err := r.retryDelay(retryAttempt) + if err != nil { + return nil, err + } + + time.Sleep(delay) + + return r.run( + fn, + request, + errorDecoder, + maxRetryAttempts, + retryAttempt+1, + decodeError(response, errorDecoder), + ) + } + + return response, nil +} + +// shouldRetry returns true if the request should be retried based on the given +// response status code. +func (r *Retrier) shouldRetry(response *http.Response) bool { + return response.StatusCode == http.StatusTooManyRequests || + response.StatusCode == http.StatusRequestTimeout || + response.StatusCode == http.StatusConflict || + response.StatusCode >= http.StatusInternalServerError +} + +// retryDelay calculates the delay time in milliseconds based on the retry attempt. +func (r *Retrier) retryDelay(retryAttempt uint) (time.Duration, error) { + // Apply exponential backoff. + delay := minRetryDelay + minRetryDelay*time.Duration(retryAttempt*retryAttempt) + + // Do not allow the number to exceed maxRetryDelay. + if delay > maxRetryDelay { + delay = maxRetryDelay + } + + // Apply some itter by randomizing the value in the range of 75%-100%. + max := big.NewInt(int64(delay / 4)) + jitter, err := rand.Int(rand.Reader, max) + if err != nil { + return 0, err + } + + delay -= time.Duration(jitter.Int64()) + + // Never sleep less than the base sleep seconds. + if delay < minRetryDelay { + delay = minRetryDelay + } + + return delay, nil +} + +type retryOptions struct { + attempts uint +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/stringer.go b/seed/go-sdk/oauth-client-credentials-default/core/stringer.go new file mode 100644 index 00000000000..000cf448641 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/stringer.go @@ -0,0 +1,13 @@ +package core + +import "encoding/json" + +// StringifyJSON returns a pretty JSON string representation of +// the given value. +func StringifyJSON(value interface{}) (string, error) { + bytes, err := json.MarshalIndent(value, "", " ") + if err != nil { + return "", err + } + return string(bytes), nil +} diff --git a/seed/go-sdk/oauth-client-credentials-default/core/time.go b/seed/go-sdk/oauth-client-credentials-default/core/time.go new file mode 100644 index 00000000000..d009ab30c90 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/core/time.go @@ -0,0 +1,137 @@ +package core + +import ( + "encoding/json" + "time" +) + +const dateFormat = "2006-01-02" + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date (e.g. 2006-01-02). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type Date struct { + t *time.Time +} + +// NewDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewDate(t time.Time) *Date { + return &Date{t: &t} +} + +// NewOptionalDate returns a new *Date. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDate(t *time.Time) *Date { + if t == nil { + return nil + } + return &Date{t: t} +} + +// Time returns the Date's underlying time, if any. If the +// date is nil, the zero value is returned. +func (d *Date) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the Date's underlying time.Time, if any. +func (d *Date) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *Date) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(dateFormat)) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(dateFormat, raw) + if err != nil { + return err + } + + *d = Date{t: &parsedTime} + return nil +} + +// DateTime wraps time.Time and adapts its JSON representation +// to conform to a RFC3339 date-time (e.g. 2017-07-21T17:32:28Z). +// +// Ref: https://ijmacd.github.io/rfc3339-iso8601 +type DateTime struct { + t *time.Time +} + +// NewDateTime returns a new *DateTime. +func NewDateTime(t time.Time) *DateTime { + return &DateTime{t: &t} +} + +// NewOptionalDateTime returns a new *DateTime. If the given time.Time +// is nil, nil will be returned. +func NewOptionalDateTime(t *time.Time) *DateTime { + if t == nil { + return nil + } + return &DateTime{t: t} +} + +// Time returns the DateTime's underlying time, if any. If the +// date-time is nil, the zero value is returned. +func (d *DateTime) Time() time.Time { + if d == nil || d.t == nil { + return time.Time{} + } + return *d.t +} + +// TimePtr returns a pointer to the DateTime's underlying time.Time, if any. +func (d *DateTime) TimePtr() *time.Time { + if d == nil || d.t == nil { + return nil + } + if d.t.IsZero() { + return nil + } + return d.t +} + +func (d *DateTime) MarshalJSON() ([]byte, error) { + if d == nil || d.t == nil { + return nil, nil + } + return json.Marshal(d.t.Format(time.RFC3339)) +} + +func (d *DateTime) UnmarshalJSON(data []byte) error { + var raw string + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + parsedTime, err := time.Parse(time.RFC3339, raw) + if err != nil { + return err + } + + *d = DateTime{t: &parsedTime} + return nil +} diff --git a/seed/go-sdk/oauth-client-credentials-default/go.mod b/seed/go-sdk/oauth-client-credentials-default/go.mod new file mode 100644 index 00000000000..651be67c608 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/go.mod @@ -0,0 +1,9 @@ +module github.com/oauth-client-credentials-default/fern + +go 1.13 + +require ( + github.com/google/uuid v1.4.0 + github.com/stretchr/testify v1.7.0 + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/seed/go-sdk/oauth-client-credentials-default/go.sum b/seed/go-sdk/oauth-client-credentials-default/go.sum new file mode 100644 index 00000000000..b3766d4366b --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/go.sum @@ -0,0 +1,14 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/seed/go-sdk/oauth-client-credentials-default/option/request_option.go b/seed/go-sdk/oauth-client-credentials-default/option/request_option.go new file mode 100644 index 00000000000..90e0a7fdd5d --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/option/request_option.go @@ -0,0 +1,41 @@ +// This file was auto-generated by Fern from our API Definition. + +package option + +import ( + core "github.com/oauth-client-credentials-default/fern/core" + http "net/http" +) + +// RequestOption adapts the behavior of an indivdual request. +type RequestOption = core.RequestOption + +// WithBaseURL sets the base URL, overriding the default +// environment, if any. +func WithBaseURL(baseURL string) *core.BaseURLOption { + return &core.BaseURLOption{ + BaseURL: baseURL, + } +} + +// WithHTTPClient uses the given HTTPClient to issue the request. +func WithHTTPClient(httpClient core.HTTPClient) *core.HTTPClientOption { + return &core.HTTPClientOption{ + HTTPClient: httpClient, + } +} + +// WithHTTPHeader adds the given http.Header to the request. +func WithHTTPHeader(httpHeader http.Header) *core.HTTPHeaderOption { + return &core.HTTPHeaderOption{ + // Clone the headers so they can't be modified after the option call. + HTTPHeader: httpHeader.Clone(), + } +} + +// WithMaxAttempts configures the maximum number of retry attempts. +func WithMaxAttempts(attempts uint) *core.MaxAttemptsOption { + return &core.MaxAttemptsOption{ + MaxAttempts: attempts, + } +} diff --git a/seed/go-sdk/oauth-client-credentials-default/pointer.go b/seed/go-sdk/oauth-client-credentials-default/pointer.go new file mode 100644 index 00000000000..6ef1f26a520 --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/pointer.go @@ -0,0 +1,132 @@ +package oauthclientcredentialsdefault + +import ( + "time" + + "github.com/google/uuid" +) + +// Bool returns a pointer to the given bool value. +func Bool(b bool) *bool { + return &b +} + +// Byte returns a pointer to the given byte value. +func Byte(b byte) *byte { + return &b +} + +// Complex64 returns a pointer to the given complex64 value. +func Complex64(c complex64) *complex64 { + return &c +} + +// Complex128 returns a pointer to the given complex128 value. +func Complex128(c complex128) *complex128 { + return &c +} + +// Float32 returns a pointer to the given float32 value. +func Float32(f float32) *float32 { + return &f +} + +// Float64 returns a pointer to the given float64 value. +func Float64(f float64) *float64 { + return &f +} + +// Int returns a pointer to the given int value. +func Int(i int) *int { + return &i +} + +// Int8 returns a pointer to the given int8 value. +func Int8(i int8) *int8 { + return &i +} + +// Int16 returns a pointer to the given int16 value. +func Int16(i int16) *int16 { + return &i +} + +// Int32 returns a pointer to the given int32 value. +func Int32(i int32) *int32 { + return &i +} + +// Int64 returns a pointer to the given int64 value. +func Int64(i int64) *int64 { + return &i +} + +// Rune returns a pointer to the given rune value. +func Rune(r rune) *rune { + return &r +} + +// String returns a pointer to the given string value. +func String(s string) *string { + return &s +} + +// Uint returns a pointer to the given uint value. +func Uint(u uint) *uint { + return &u +} + +// Uint8 returns a pointer to the given uint8 value. +func Uint8(u uint8) *uint8 { + return &u +} + +// Uint16 returns a pointer to the given uint16 value. +func Uint16(u uint16) *uint16 { + return &u +} + +// Uint32 returns a pointer to the given uint32 value. +func Uint32(u uint32) *uint32 { + return &u +} + +// Uint64 returns a pointer to the given uint64 value. +func Uint64(u uint64) *uint64 { + return &u +} + +// Uintptr returns a pointer to the given uintptr value. +func Uintptr(u uintptr) *uintptr { + return &u +} + +// UUID returns a pointer to the given uuid.UUID value. +func UUID(u uuid.UUID) *uuid.UUID { + return &u +} + +// Time returns a pointer to the given time.Time value. +func Time(t time.Time) *time.Time { + return &t +} + +// MustParseDate attempts to parse the given string as a +// date time.Time, and panics upon failure. +func MustParseDate(date string) time.Time { + t, err := time.Parse("2006-01-02", date) + if err != nil { + panic(err) + } + return t +} + +// MustParseDateTime attempts to parse the given string as a +// datetime time.Time, and panics upon failure. +func MustParseDateTime(datetime string) time.Time { + t, err := time.Parse(time.RFC3339, datetime) + if err != nil { + panic(err) + } + return t +} diff --git a/seed/go-sdk/oauth-client-credentials-default/snippet-templates.json b/seed/go-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/go-sdk/oauth-client-credentials-default/snippet.json b/seed/go-sdk/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..1c8ce3363eb --- /dev/null +++ b/seed/go-sdk/oauth-client-credentials-default/snippet.json @@ -0,0 +1,14 @@ +{ + "endpoints": [ + { + "id": { + "path": "/token", + "method": "POST" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/oauth-client-credentials-default/fern\"\n\tfernclient \"github.com/oauth-client-credentials-default/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.Auth.GetToken(\n\tcontext.TODO(),\n\t\u0026fern.GetTokenRequest{\n\t\tClientId: \"string\",\n\t\tClientSecret: \"string\",\n\t},\n)\n" + } + } + ] +} \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/java-model/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..8598a73092a --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Compile + run: ./gradlew compileJava + + test: + needs: [ compile ] + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Test + run: ./gradlew test + publish: + needs: [ compile, test ] + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Publish to maven + run: | + ./gradlew publish + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + MAVEN_PUBLISH_REGISTRY_URL: "" diff --git a/seed/java-model/oauth-client-credentials-default/.gitignore b/seed/java-model/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..d4199abc2cd --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.gitignore @@ -0,0 +1,24 @@ +*.class +.project +.gradle +? +.classpath +.checkstyle +.settings +.node +build + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Eclipse/IntelliJ APT +generated_src/ +generated_testSrc/ +generated/ + +bin +build \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.inputs/config.json b/seed/java-model/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..27b20c665dc --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,31 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "maven", + "registryUrl": "", + "coordinate": "com.fern:oauth-client-credentials-default", + "usernameEnvironmentVariable": "", + "passwordEnvironmentVariable": "", + "signature": null + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.inputs/ir.json b/seed/java-model/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..59adde187d0 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,694 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.mock/definition/api.yml b/seed/java-model/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/java-model/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.mock/fern.config.json b/seed/java-model/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/java-model/oauth-client-credentials-default/.mock/generators.yml b/seed/java-model/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/java-model/oauth-client-credentials-default/build.gradle b/seed/java-model/oauth-client-credentials-default/build.gradle new file mode 100644 index 00000000000..052f3981465 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/build.gradle @@ -0,0 +1,67 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'com.diffplug.spotless' version '6.11.0' +} + +repositories { + mavenCentral() + maven { + url 'https://s01.oss.sonatype.org/content/repositories/releases/' + } +} + +dependencies { + api 'com.fasterxml.jackson.core:jackson-databind:2.13.0' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.3' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3' +} + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +spotless { + java { + palantirJavaFormat() + } +} + +java { + withSourcesJar() + withJavadocJar() +} + +test { + useJUnitPlatform() + testLogging { + showStandardStreams = true + } +} +publishing { + publications { + maven(MavenPublication) { + groupId = 'com.fern' + artifactId = 'oauth-client-credentials-default' + version = '0.0.1' + from components.java + pom { + scm { + connection = 'scm:git:git://github.com/oauth-client-credentials-default/fern.git' + developerConnection = 'scm:git:git://github.com/oauth-client-credentials-default/fern.git' + url = 'https://github.com/oauth-client-credentials-default/fern' + } + } + } + } + repositories { + maven { + url "$System.env.MAVEN_PUBLISH_REGISTRY_URL" + credentials { + username "$System.env.MAVEN_USERNAME" + password "$System.env.MAVEN_PASSWORD" + } + } + } +} + diff --git a/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar b/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d64cd4917707c1f8861d8cb53dd15194d4248596 GIT binary patch literal 43462 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 literal 0 HcmV?d00001 diff --git a/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties b/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..1af9e0930b8 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/seed/java-model/oauth-client-credentials-default/gradlew b/seed/java-model/oauth-client-credentials-default/gradlew new file mode 100755 index 00000000000..1aa94a42690 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/seed/java-model/oauth-client-credentials-default/gradlew.bat b/seed/java-model/oauth-client-credentials-default/gradlew.bat new file mode 100644 index 00000000000..6689b85beec --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/seed/java-model/oauth-client-credentials-default/settings.gradle b/seed/java-model/oauth-client-credentials-default/settings.gradle new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-model/oauth-client-credentials-default/snippet-templates.json b/seed/java-model/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-model/oauth-client-credentials-default/snippet.json b/seed/java-model/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java new file mode 100644 index 00000000000..1299f55e57e --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java @@ -0,0 +1,55 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} diff --git a/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java new file mode 100644 index 00000000000..a91b9c0f6c5 --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java @@ -0,0 +1,36 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() {} + + public static String stringify(Object o) { + try { + return JSON_MAPPER + .setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } +} diff --git a/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/model/auth/TokenResponse.java b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/model/auth/TokenResponse.java new file mode 100644 index 00000000000..e775525c80c --- /dev/null +++ b/seed/java-model/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/model/auth/TokenResponse.java @@ -0,0 +1,108 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.model.auth; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.oauthClientCredentialsDefault.core.ObjectMappers; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonDeserialize(builder = TokenResponse.Builder.class) +public final class TokenResponse { + private final String accessToken; + + private final int expiresIn; + + private TokenResponse(String accessToken, int expiresIn) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + } + + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + @JsonProperty("expires_in") + public int getExpiresIn() { + return expiresIn; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenResponse && equalTo((TokenResponse) other); + } + + private boolean equalTo(TokenResponse other) { + return accessToken.equals(other.accessToken) && expiresIn == other.expiresIn; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.accessToken, this.expiresIn); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static AccessTokenStage builder() { + return new Builder(); + } + + public interface AccessTokenStage { + ExpiresInStage accessToken(String accessToken); + + Builder from(TokenResponse other); + } + + public interface ExpiresInStage { + _FinalStage expiresIn(int expiresIn); + } + + public interface _FinalStage { + TokenResponse build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements AccessTokenStage, ExpiresInStage, _FinalStage { + private String accessToken; + + private int expiresIn; + + private Builder() {} + + @java.lang.Override + public Builder from(TokenResponse other) { + accessToken(other.getAccessToken()); + expiresIn(other.getExpiresIn()); + return this; + } + + @java.lang.Override + @JsonSetter("access_token") + public ExpiresInStage accessToken(String accessToken) { + this.accessToken = accessToken; + return this; + } + + @java.lang.Override + @JsonSetter("expires_in") + public _FinalStage expiresIn(int expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + @java.lang.Override + public TokenResponse build() { + return new TokenResponse(accessToken, expiresIn); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/java-sdk/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..8598a73092a --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: ci + +on: [push] + +jobs: + compile: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Compile + run: ./gradlew compileJava + + test: + needs: [ compile ] + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Test + run: ./gradlew test + publish: + needs: [ compile, test ] + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Publish to maven + run: | + ./gradlew publish + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + MAVEN_PUBLISH_REGISTRY_URL: "" diff --git a/seed/java-sdk/oauth-client-credentials-default/.gitignore b/seed/java-sdk/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..d4199abc2cd --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.gitignore @@ -0,0 +1,24 @@ +*.class +.project +.gradle +? +.classpath +.checkstyle +.settings +.node +build + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Eclipse/IntelliJ APT +generated_src/ +generated_testSrc/ +generated/ + +bin +build \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/java-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..27b20c665dc --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,31 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "maven", + "registryUrl": "", + "coordinate": "com.fern:oauth-client-credentials-default", + "usernameEnvironmentVariable": "", + "passwordEnvironmentVariable": "", + "signature": null + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/java-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..59adde187d0 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,694 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.mock/definition/api.yml b/seed/java-sdk/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/java-sdk/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.mock/fern.config.json b/seed/java-sdk/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/.mock/generators.yml b/seed/java-sdk/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/java-sdk/oauth-client-credentials-default/build.gradle b/seed/java-sdk/oauth-client-credentials-default/build.gradle new file mode 100644 index 00000000000..6601fd8e9f2 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/build.gradle @@ -0,0 +1,70 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'com.diffplug.spotless' version '6.11.0' +} + +repositories { + mavenCentral() + maven { + url 'https://s01.oss.sonatype.org/content/repositories/releases/' + } +} + +dependencies { + api 'com.squareup.okhttp3:okhttp:4.12.0' + api 'com.fasterxml.jackson.core:jackson-databind:2.13.0' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.3' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +} + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +spotless { + java { + palantirJavaFormat() + } +} + +java { + withSourcesJar() + withJavadocJar() +} + +test { + useJUnitPlatform() + testLogging { + showStandardStreams = true + } +} +publishing { + publications { + maven(MavenPublication) { + groupId = 'com.fern' + artifactId = 'oauth-client-credentials-default' + version = '0.0.1' + from components.java + pom { + scm { + connection = 'scm:git:git://github.com/oauth-client-credentials-default/fern.git' + developerConnection = 'scm:git:git://github.com/oauth-client-credentials-default/fern.git' + url = 'https://github.com/oauth-client-credentials-default/fern' + } + } + } + } + repositories { + maven { + url "$System.env.MAVEN_PUBLISH_REGISTRY_URL" + credentials { + username "$System.env.MAVEN_USERNAME" + password "$System.env.MAVEN_PASSWORD" + } + } + } +} + diff --git a/seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar b/seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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

NnX)EH+Nua)3Y(c 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/seed/java-sdk/oauth-client-credentials-default/gradlew.bat b/seed/java-sdk/oauth-client-credentials-default/gradlew.bat new file mode 100644 index 00000000000..7101f8e4676 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/seed/java-sdk/oauth-client-credentials-default/sample-app/build.gradle b/seed/java-sdk/oauth-client-credentials-default/sample-app/build.gradle new file mode 100644 index 00000000000..4ee8f227b7a --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/sample-app/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java-library' +} + +repositories { + mavenCentral() + maven { + url 'https://s01.oss.sonatype.org/content/repositories/releases/' + } +} + +dependencies { + implementation rootProject +} + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + diff --git a/seed/java-sdk/oauth-client-credentials-default/sample-app/src/main/java/sample/App.java b/seed/java-sdk/oauth-client-credentials-default/sample-app/src/main/java/sample/App.java new file mode 100644 index 00000000000..356de5a3f34 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/sample-app/src/main/java/sample/App.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package sample; + +import java.lang.String; + +public final class App { + public static void main(String[] args) { + // import com.seed.oauthClientCredentialsDefault.SeedOauthClientCredentialsDefaultClient + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/settings.gradle b/seed/java-sdk/oauth-client-credentials-default/settings.gradle new file mode 100644 index 00000000000..aed36fec10b --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/settings.gradle @@ -0,0 +1 @@ +include 'sample-app' \ No newline at end of file diff --git a/seed/java-sdk/oauth-client-credentials-default/snippet-templates.json b/seed/java-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-sdk/oauth-client-credentials-default/snippet.json b/seed/java-sdk/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.java new file mode 100644 index 00000000000..313b7d4e828 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault; + +import com.seed.oauthClientCredentialsDefault.core.ClientOptions; +import com.seed.oauthClientCredentialsDefault.core.Suppliers; +import com.seed.oauthClientCredentialsDefault.resources.auth.AuthClient; +import java.util.function.Supplier; + +public class SeedOauthClientCredentialsDefaultClient { + protected final ClientOptions clientOptions; + + protected final Supplier authClient; + + public SeedOauthClientCredentialsDefaultClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.authClient = Suppliers.memoize(() -> new AuthClient(clientOptions)); + } + + public AuthClient auth() { + return this.authClient.get(); + } + + public static SeedOauthClientCredentialsDefaultClientBuilder builder() { + return new SeedOauthClientCredentialsDefaultClientBuilder(); + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClientBuilder.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClientBuilder.java new file mode 100644 index 00000000000..b142daeae69 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClientBuilder.java @@ -0,0 +1,34 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault; + +import com.seed.oauthClientCredentialsDefault.core.ClientOptions; +import com.seed.oauthClientCredentialsDefault.core.Environment; + +public final class SeedOauthClientCredentialsDefaultClientBuilder { + private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder(); + + private String token = null; + + private Environment environment; + + /** + * Sets token + */ + public SeedOauthClientCredentialsDefaultClientBuilder token(String token) { + this.token = token; + return this; + } + + public SeedOauthClientCredentialsDefaultClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + public SeedOauthClientCredentialsDefaultClient build() { + this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token); + clientOptionsBuilder.environment(this.environment); + return new SeedOauthClientCredentialsDefaultClient(clientOptionsBuilder.build()); + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ApiError.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ApiError.java new file mode 100644 index 00000000000..c262c4e5c23 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ApiError.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +public final class ApiError extends RuntimeException { + private final int statusCode; + + private final Object body; + + public ApiError(int statusCode, Object body) { + this.statusCode = statusCode; + this.body = body; + } + + public int statusCode() { + return this.statusCode; + } + + public Object body() { + return this.body; + } + + @java.lang.Override + public String toString() { + return "ApiError{" + "statusCode: " + statusCode + ", body: " + body + "}"; + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ClientOptions.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ClientOptions.java new file mode 100644 index 00000000000..715f29a21f5 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ClientOptions.java @@ -0,0 +1,100 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import okhttp3.OkHttpClient; + +public final class ClientOptions { + private final Environment environment; + + private final Map headers; + + private final Map> headerSuppliers; + + private final OkHttpClient httpClient; + + private ClientOptions( + Environment environment, + Map headers, + Map> headerSuppliers, + OkHttpClient httpClient) { + this.environment = environment; + this.headers = new HashMap<>(); + this.headers.putAll(headers); + this.headers.putAll(Map.of("X-Fern-Language", "JAVA")); + this.headerSuppliers = headerSuppliers; + this.httpClient = httpClient; + ; + } + + public Environment environment() { + return this.environment; + } + + public Map headers(RequestOptions requestOptions) { + Map values = new HashMap<>(this.headers); + headerSuppliers.forEach((key, supplier) -> { + values.put(key, supplier.get()); + }); + if (requestOptions != null) { + values.putAll(requestOptions.getHeaders()); + } + return values; + } + + public OkHttpClient httpClient() { + return this.httpClient; + } + + public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.httpClient; + } + return this.httpClient + .newBuilder() + .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private Environment environment; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + public Builder environment(Environment environment) { + this.environment = environment; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + public ClientOptions build() { + OkHttpClient okhttpClient = new OkHttpClient.Builder() + .addInterceptor(new RetryInterceptor(3)) + .build(); + return new ClientOptions(environment, headers, headerSuppliers, okhttpClient); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java new file mode 100644 index 00000000000..1299f55e57e --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/DateTimeDeserializer.java @@ -0,0 +1,55 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Environment.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Environment.java new file mode 100644 index 00000000000..8c1944c5e92 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Environment.java @@ -0,0 +1,20 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +public final class Environment { + private final String url; + + private Environment(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } + + public static Environment custom(String url) { + return new Environment(url); + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/MediaTypes.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/MediaTypes.java new file mode 100644 index 00000000000..747d3d47ac6 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/MediaTypes.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import okhttp3.MediaType; + +public final class MediaTypes { + + public static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); + + private MediaTypes() {} +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java new file mode 100644 index 00000000000..a91b9c0f6c5 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/ObjectMappers.java @@ -0,0 +1,36 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() {} + + public static String stringify(Object o) { + try { + return JSON_MAPPER + .setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RequestOptions.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RequestOptions.java new file mode 100644 index 00000000000..e50bbe202af --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RequestOptions.java @@ -0,0 +1,71 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +public final class RequestOptions { + private final String token; + + private final Optional timeout; + + private final TimeUnit timeoutTimeUnit; + + private RequestOptions(String token, Optional timeout, TimeUnit timeoutTimeUnit) { + this.token = token; + this.timeout = timeout; + this.timeoutTimeUnit = timeoutTimeUnit; + } + + public Optional getTimeout() { + return timeout; + } + + public TimeUnit getTimeoutTimeUnit() { + return timeoutTimeUnit; + } + + public Map getHeaders() { + Map headers = new HashMap<>(); + if (this.token != null) { + headers.put("Authorization", "Bearer " + this.token); + } + return headers; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private String token = null; + + private Optional timeout = null; + + private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; + + public Builder token(String token) { + this.token = token; + return this; + } + + public Builder timeout(Integer timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) { + this.timeout = Optional.of(timeout); + this.timeoutTimeUnit = timeoutTimeUnit; + return this; + } + + public RequestOptions build() { + return new RequestOptions(token, timeout, timeoutTimeUnit); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RetryInterceptor.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RetryInterceptor.java new file mode 100644 index 00000000000..c36a09abd5f --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/RetryInterceptor.java @@ -0,0 +1,78 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import java.io.IOException; +import java.time.Duration; +import java.util.Optional; +import java.util.Random; +import okhttp3.Interceptor; +import okhttp3.Response; + +public class RetryInterceptor implements Interceptor { + + private static final Duration ONE_SECOND = Duration.ofSeconds(1); + private final ExponentialBackoff backoff; + private final Random random = new Random(); + + public RetryInterceptor(int maxRetries) { + this.backoff = new ExponentialBackoff(maxRetries); + } + + @Override + public Response intercept(Chain chain) throws IOException { + Response response = chain.proceed(chain.request()); + + if (shouldRetry(response.code())) { + return retryChain(response, chain); + } + + return response; + } + + private Response retryChain(Response response, Chain chain) throws IOException { + Optional nextBackoff = this.backoff.nextBackoff(); + while (nextBackoff.isPresent()) { + try { + Thread.sleep(nextBackoff.get().toMillis()); + } catch (InterruptedException e) { + throw new IOException("Interrupted while trying request", e); + } + response.close(); + response = chain.proceed(chain.request()); + if (shouldRetry(response.code())) { + nextBackoff = this.backoff.nextBackoff(); + } else { + return response; + } + } + + return response; + } + + private static boolean shouldRetry(int statusCode) { + return statusCode == 408 || statusCode == 409 || statusCode == 429 || statusCode >= 500; + } + + private final class ExponentialBackoff { + + private final int maxNumRetries; + + private int retryNumber = 0; + + ExponentialBackoff(int maxNumRetries) { + this.maxNumRetries = maxNumRetries; + } + + public Optional nextBackoff() { + retryNumber += 1; + if (retryNumber > maxNumRetries) { + return Optional.empty(); + } + + int upperBound = (int) Math.pow(2, retryNumber); + return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound))); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Stream.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Stream.java new file mode 100644 index 00000000000..c0ca3207346 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Stream.java @@ -0,0 +1,97 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import java.io.Reader; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Scanner; + +/** + * The {@code Stream} class implmenets {@link Iterable} to provide a simple mechanism for reading and parsing + * objects of a given type from data streamed via a {@link Reader} using a specified delimiter. + *

+ * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a + * {@code Scanner} to block during iteration if the next object is not available. + * + * @param The type of objects in the stream. + */ +public final class Stream implements Iterable { + /** + * The {@link Class} of the objects in the stream. + */ + private final Class valueType; + /** + * The {@link Scanner} used for reading from the input stream and blocking when neede during iteration. + */ + private final Scanner scanner; + + /** + * Constructs a new {@code Stream} with the specified value type, reader, and delimiter. + * + * @param valueType The class of the objects in the stream. + * @param reader The reader that provides the streamed data. + * @param delimiter The delimiter used to separate elements in the stream. + */ + public Stream(Class valueType, Reader reader, String delimiter) { + this.scanner = new Scanner(reader).useDelimiter(delimiter); + this.valueType = valueType; + } + + /** + * Returns an iterator over the elements in this stream that blocks during iteration when the next object is + * not yet available. + * + * @return An iterator that can be used to traverse the elements in the stream. + */ + @Override + public Iterator iterator() { + return new Iterator() { + /** + * Returns {@code true} if there are more elements in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + */ + @Override + public boolean hasNext() { + return scanner.hasNext(); + } + + /** + * Returns the next element in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return The next element in the stream. + * @throws NoSuchElementException If there are no more elements in the stream. + */ + @Override + public T next() { + if (!scanner.hasNext()) { + throw new NoSuchElementException(); + } else { + try { + T parsedResponse = ObjectMappers.JSON_MAPPER.readValue( + scanner.next().trim(), valueType); + return parsedResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + /** + * Removing elements from {@code Stream} is not supported. + * + * @throws UnsupportedOperationException Always, as removal is not supported. + */ + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Suppliers.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Suppliers.java new file mode 100644 index 00000000000..43ae7291c8c --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/core/Suppliers.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.core; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public final class Suppliers { + private Suppliers() {} + + public static Supplier memoize(Supplier delegate) { + AtomicReference value = new AtomicReference<>(); + return () -> { + T val = value.get(); + if (val == null) { + val = value.updateAndGet(cur -> cur == null ? Objects.requireNonNull(delegate.get()) : cur); + } + return val; + }; + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/AuthClient.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/AuthClient.java new file mode 100644 index 00000000000..1ecdf428d13 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/AuthClient.java @@ -0,0 +1,69 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.resources.auth; + +import com.seed.oauthClientCredentialsDefault.core.ApiError; +import com.seed.oauthClientCredentialsDefault.core.ClientOptions; +import com.seed.oauthClientCredentialsDefault.core.MediaTypes; +import com.seed.oauthClientCredentialsDefault.core.ObjectMappers; +import com.seed.oauthClientCredentialsDefault.core.RequestOptions; +import com.seed.oauthClientCredentialsDefault.resources.auth.requests.GetTokenRequest; +import com.seed.oauthClientCredentialsDefault.resources.auth.types.TokenResponse; +import java.io.IOException; +import okhttp3.Headers; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class AuthClient { + protected final ClientOptions clientOptions; + + public AuthClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + public TokenResponse getToken(GetTokenRequest request) { + return getToken(request, null); + } + + public TokenResponse getToken(GetTokenRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("token") + .build(); + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (Exception e) { + throw new RuntimeException(e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .build(); + try { + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + Response response = client.newCall(okhttpRequest).execute(); + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return ObjectMappers.JSON_MAPPER.readValue(responseBody.string(), TokenResponse.class); + } + throw new ApiError( + response.code(), + ObjectMappers.JSON_MAPPER.readValue( + responseBody != null ? responseBody.string() : "{}", Object.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/requests/GetTokenRequest.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/requests/GetTokenRequest.java new file mode 100644 index 00000000000..8285924d1c7 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/requests/GetTokenRequest.java @@ -0,0 +1,128 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.resources.auth.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.oauthClientCredentialsDefault.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonDeserialize(builder = GetTokenRequest.Builder.class) +public final class GetTokenRequest { + private final String clientId; + + private final String clientSecret; + + private final Map additionalProperties; + + private GetTokenRequest(String clientId, String clientSecret, Map additionalProperties) { + this.clientId = clientId; + this.clientSecret = clientSecret; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("client_id") + public String getClientId() { + return clientId; + } + + @JsonProperty("client_secret") + public String getClientSecret() { + return clientSecret; + } + + @JsonProperty("grant_type") + public String getGrantType() { + return "client_credentials"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokenRequest && equalTo((GetTokenRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(GetTokenRequest other) { + return clientId.equals(other.clientId) && clientSecret.equals(other.clientSecret); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.clientId, this.clientSecret); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ClientIdStage builder() { + return new Builder(); + } + + public interface ClientIdStage { + ClientSecretStage clientId(String clientId); + + Builder from(GetTokenRequest other); + } + + public interface ClientSecretStage { + _FinalStage clientSecret(String clientSecret); + } + + public interface _FinalStage { + GetTokenRequest build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements ClientIdStage, ClientSecretStage, _FinalStage { + private String clientId; + + private String clientSecret; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(GetTokenRequest other) { + clientId(other.getClientId()); + clientSecret(other.getClientSecret()); + return this; + } + + @java.lang.Override + @JsonSetter("client_id") + public ClientSecretStage clientId(String clientId) { + this.clientId = clientId; + return this; + } + + @java.lang.Override + @JsonSetter("client_secret") + public _FinalStage clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + @java.lang.Override + public GetTokenRequest build() { + return new GetTokenRequest(clientId, clientSecret, additionalProperties); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/types/TokenResponse.java b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/types/TokenResponse.java new file mode 100644 index 00000000000..2e4190e22f1 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/main/java/com/seed/oauthClientCredentialsDefault/resources/auth/types/TokenResponse.java @@ -0,0 +1,123 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault.resources.auth.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.oauthClientCredentialsDefault.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonDeserialize(builder = TokenResponse.Builder.class) +public final class TokenResponse { + private final String accessToken; + + private final int expiresIn; + + private final Map additionalProperties; + + private TokenResponse(String accessToken, int expiresIn, Map additionalProperties) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + @JsonProperty("expires_in") + public int getExpiresIn() { + return expiresIn; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenResponse && equalTo((TokenResponse) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(TokenResponse other) { + return accessToken.equals(other.accessToken) && expiresIn == other.expiresIn; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.accessToken, this.expiresIn); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static AccessTokenStage builder() { + return new Builder(); + } + + public interface AccessTokenStage { + ExpiresInStage accessToken(String accessToken); + + Builder from(TokenResponse other); + } + + public interface ExpiresInStage { + _FinalStage expiresIn(int expiresIn); + } + + public interface _FinalStage { + TokenResponse build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements AccessTokenStage, ExpiresInStage, _FinalStage { + private String accessToken; + + private int expiresIn; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(TokenResponse other) { + accessToken(other.getAccessToken()); + expiresIn(other.getExpiresIn()); + return this; + } + + @java.lang.Override + @JsonSetter("access_token") + public ExpiresInStage accessToken(String accessToken) { + this.accessToken = accessToken; + return this; + } + + @java.lang.Override + @JsonSetter("expires_in") + public _FinalStage expiresIn(int expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + @java.lang.Override + public TokenResponse build() { + return new TokenResponse(accessToken, expiresIn, additionalProperties); + } + } +} diff --git a/seed/java-sdk/oauth-client-credentials-default/src/test/java/com/seed/oauthClientCredentialsDefault/TestClient.java b/seed/java-sdk/oauth-client-credentials-default/src/test/java/com/seed/oauthClientCredentialsDefault/TestClient.java new file mode 100644 index 00000000000..02668e48ad4 --- /dev/null +++ b/seed/java-sdk/oauth-client-credentials-default/src/test/java/com/seed/oauthClientCredentialsDefault/TestClient.java @@ -0,0 +1,11 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.oauthClientCredentialsDefault; + +public final class TestClient { + public void test() { + // Add tests here and mark this file in .fernignore + assert true; + } +} diff --git a/seed/java-spring/oauth-client-credentials-default/.inputs/config.json b/seed/java-spring/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..cd6b9b51711 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,20 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/.inputs/ir.json b/seed/java-spring/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..59adde187d0 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,694 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/.mock/definition/api.yml b/seed/java-spring/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/java-spring/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/.mock/fern.config.json b/seed/java-spring/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/.mock/generators.yml b/seed/java-spring/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/java-spring/oauth-client-credentials-default/core/APIException.java b/seed/java-spring/oauth-client-credentials-default/core/APIException.java new file mode 100644 index 00000000000..27289cf9b2e --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/core/APIException.java @@ -0,0 +1,10 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package core; + +import java.lang.Exception; + +public class APIException extends Exception { +} diff --git a/seed/java-spring/oauth-client-credentials-default/core/BearerAuth.java b/seed/java-spring/oauth-client-credentials-default/core/BearerAuth.java new file mode 100644 index 00000000000..58a05842c2f --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/core/BearerAuth.java @@ -0,0 +1,30 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package core; + +import com.fasterxml.jackson.annotation.JsonValue; +import java.lang.String; + +public final class BearerAuth { + private final String token; + + private BearerAuth(String token) { + this.token = token; + } + + @JsonValue + public String getToken() { + return token; + } + + @java.lang.Override + public String toString() { + return "Bearer " + getToken(); + } + + public static BearerAuth of(String token) { + return new BearerAuth(token.startsWith("Bearer ") ? token.substring(7) : token); + } +} diff --git a/seed/java-spring/oauth-client-credentials-default/core/DateTimeDeserializer.java b/seed/java-spring/oauth-client-credentials-default/core/DateTimeDeserializer.java new file mode 100644 index 00000000000..3d3174aec00 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/core/DateTimeDeserializer.java @@ -0,0 +1,56 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} \ No newline at end of file diff --git a/seed/java-spring/oauth-client-credentials-default/core/ObjectMappers.java b/seed/java-spring/oauth-client-credentials-default/core/ObjectMappers.java new file mode 100644 index 00000000000..e02822614a8 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/core/ObjectMappers.java @@ -0,0 +1,41 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.lang.Integer; +import java.lang.Object; +import java.lang.String; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() { + } + + public static String stringify(Object o) { + try { + return JSON_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } + catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } + } diff --git a/seed/java-spring/oauth-client-credentials-default/resources/auth/AuthService.java b/seed/java-spring/oauth-client-credentials-default/resources/auth/AuthService.java new file mode 100644 index 00000000000..f0096d10957 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/resources/auth/AuthService.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package resources.auth; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import resources.auth.requests.GetTokenRequest; +import resources.auth.types.TokenResponse; + +@RequestMapping( + path = "/" +) +public interface AuthService { + @PostMapping( + value = "/token", + produces = "application/json", + consumes = "application/json" + ) + TokenResponse getToken(@RequestBody GetTokenRequest body); +} diff --git a/seed/java-spring/oauth-client-credentials-default/resources/auth/requests/GetTokenRequest.java b/seed/java-spring/oauth-client-credentials-default/resources/auth/requests/GetTokenRequest.java new file mode 100644 index 00000000000..169bd910b86 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/resources/auth/requests/GetTokenRequest.java @@ -0,0 +1,121 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package resources.auth.requests; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import core.ObjectMappers; +import java.lang.Object; +import java.lang.String; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonDeserialize( + builder = GetTokenRequest.Builder.class +) +public final class GetTokenRequest { + private final String clientId; + + private final String clientSecret; + + private GetTokenRequest(String clientId, String clientSecret) { + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + @JsonProperty("client_id") + public String getClientId() { + return clientId; + } + + @JsonProperty("client_secret") + public String getClientSecret() { + return clientSecret; + } + + @JsonProperty("grant_type") + public String getGrantType() { + return "client_credentials"; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof GetTokenRequest && equalTo((GetTokenRequest) other); + } + + private boolean equalTo(GetTokenRequest other) { + return clientId.equals(other.clientId) && clientSecret.equals(other.clientSecret); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.clientId, this.clientSecret); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static ClientIdStage builder() { + return new Builder(); + } + + public interface ClientIdStage { + ClientSecretStage clientId(String clientId); + + Builder from(GetTokenRequest other); + } + + public interface ClientSecretStage { + _FinalStage clientSecret(String clientSecret); + } + + public interface _FinalStage { + GetTokenRequest build(); + } + + @JsonIgnoreProperties( + ignoreUnknown = true + ) + public static final class Builder implements ClientIdStage, ClientSecretStage, _FinalStage { + private String clientId; + + private String clientSecret; + + private Builder() { + } + + @java.lang.Override + public Builder from(GetTokenRequest other) { + clientId(other.getClientId()); + clientSecret(other.getClientSecret()); + return this; + } + + @java.lang.Override + @JsonSetter("client_id") + public ClientSecretStage clientId(String clientId) { + this.clientId = clientId; + return this; + } + + @java.lang.Override + @JsonSetter("client_secret") + public _FinalStage clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + @java.lang.Override + public GetTokenRequest build() { + return new GetTokenRequest(clientId, clientSecret); + } + } +} diff --git a/seed/java-spring/oauth-client-credentials-default/resources/auth/types/TokenResponse.java b/seed/java-spring/oauth-client-credentials-default/resources/auth/types/TokenResponse.java new file mode 100644 index 00000000000..5108882b0a4 --- /dev/null +++ b/seed/java-spring/oauth-client-credentials-default/resources/auth/types/TokenResponse.java @@ -0,0 +1,116 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package resources.auth.types; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import core.ObjectMappers; +import java.lang.Object; +import java.lang.String; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonDeserialize( + builder = TokenResponse.Builder.class +) +public final class TokenResponse { + private final String accessToken; + + private final int expiresIn; + + private TokenResponse(String accessToken, int expiresIn) { + this.accessToken = accessToken; + this.expiresIn = expiresIn; + } + + @JsonProperty("access_token") + public String getAccessToken() { + return accessToken; + } + + @JsonProperty("expires_in") + public int getExpiresIn() { + return expiresIn; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof TokenResponse && equalTo((TokenResponse) other); + } + + private boolean equalTo(TokenResponse other) { + return accessToken.equals(other.accessToken) && expiresIn == other.expiresIn; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.accessToken, this.expiresIn); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static AccessTokenStage builder() { + return new Builder(); + } + + public interface AccessTokenStage { + ExpiresInStage accessToken(String accessToken); + + Builder from(TokenResponse other); + } + + public interface ExpiresInStage { + _FinalStage expiresIn(int expiresIn); + } + + public interface _FinalStage { + TokenResponse build(); + } + + @JsonIgnoreProperties( + ignoreUnknown = true + ) + public static final class Builder implements AccessTokenStage, ExpiresInStage, _FinalStage { + private String accessToken; + + private int expiresIn; + + private Builder() { + } + + @java.lang.Override + public Builder from(TokenResponse other) { + accessToken(other.getAccessToken()); + expiresIn(other.getExpiresIn()); + return this; + } + + @java.lang.Override + @JsonSetter("access_token") + public ExpiresInStage accessToken(String accessToken) { + this.accessToken = accessToken; + return this; + } + + @java.lang.Override + @JsonSetter("expires_in") + public _FinalStage expiresIn(int expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + @java.lang.Override + public TokenResponse build() { + return new TokenResponse(accessToken, expiresIn); + } + } +} diff --git a/seed/java-spring/oauth-client-credentials-default/snippet-templates.json b/seed/java-spring/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/java-spring/oauth-client-credentials-default/snippet.json b/seed/java-spring/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/openapi/oauth-client-credentials-default/.inputs/config.json b/seed/openapi/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..cd6b9b51711 --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,20 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/openapi/oauth-client-credentials-default/.inputs/ir.json b/seed/openapi/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..c76223835a0 --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,699 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + } + ] + }, + "examples": [], + "referencedTypes": [], + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "basePath": null, + "pathParameters": [], + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + }, + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "services": { + "service_auth": { + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "endpoints": [ + { + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + }, + "errors": [], + "auth": false, + "examples": [], + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + } + ], + "headers": [], + "pathParameters": [] + } + } +} \ No newline at end of file diff --git a/seed/openapi/oauth-client-credentials-default/.mock/definition/api.yml b/seed/openapi/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/openapi/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/openapi/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/openapi/oauth-client-credentials-default/.mock/fern.config.json b/seed/openapi/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/openapi/oauth-client-credentials-default/.mock/generators.yml b/seed/openapi/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/openapi/oauth-client-credentials-default/openapi.yml b/seed/openapi/oauth-client-credentials-default/openapi.yml new file mode 100644 index 00000000000..3960b90e8d9 --- /dev/null +++ b/seed/openapi/oauth-client-credentials-default/openapi.yml @@ -0,0 +1,55 @@ +openapi: 3.0.1 +info: + title: oauth-client-credentials-default + version: '' +paths: + /token: + post: + operationId: auth_getToken + tags: + - Auth + parameters: [] + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/TokenResponse' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + client_id: + type: string + client_secret: + type: string + grant_type: + type: string + enum: + - client_credentials + required: + - client_id + - client_secret + - grant_type +components: + schemas: + TokenResponse: + title: TokenResponse + type: object + description: An OAuth token response. + properties: + access_token: + type: string + expires_in: + type: integer + required: + - access_token + - expires_in + securitySchemes: + BearerAuth: + type: http + scheme: bearer diff --git a/seed/openapi/oauth-client-credentials-default/snippet-templates.json b/seed/openapi/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/openapi/oauth-client-credentials-default/snippet.json b/seed/openapi/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/postman/oauth-client-credentials-default/.inputs/config.json b/seed/postman/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..cd6b9b51711 --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,20 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/postman/oauth-client-credentials-default/.inputs/ir.json b/seed/postman/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..c76223835a0 --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,699 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + } + ] + }, + "examples": [], + "referencedTypes": [], + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "basePath": null, + "pathParameters": [], + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + }, + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "services": { + "service_auth": { + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "endpoints": [ + { + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + }, + "errors": [], + "auth": false, + "examples": [], + "availability": { + "status": "GENERAL_AVAILABILITY", + "message": null + }, + "docs": null + } + ], + "headers": [], + "pathParameters": [] + } + } +} \ No newline at end of file diff --git a/seed/postman/oauth-client-credentials-default/.mock/definition/api.yml b/seed/postman/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/postman/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/postman/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/postman/oauth-client-credentials-default/.mock/fern.config.json b/seed/postman/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/postman/oauth-client-credentials-default/.mock/generators.yml b/seed/postman/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/postman/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/postman/oauth-client-credentials-default/snippet-templates.json b/seed/postman/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/postman/oauth-client-credentials-default/snippet.json b/seed/postman/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/pydantic/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/pydantic/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..13313993739 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: ci + +on: [push] +jobs: + compile: + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Compile + run: poetry run mypy . + test: + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Test + run: fern test --command "poetry run pytest -rP ." + + publish: + needs: [compile, test] + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Publish to pypi + run: | + poetry config repositories.remote + poetry --no-interaction -v publish --build --repository remote --username "$" --password "$" + env: + : ${{ secrets. }} + : ${{ secrets. }} diff --git a/seed/pydantic/oauth-client-credentials-default/.gitignore b/seed/pydantic/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..42cb863501e --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.gitignore @@ -0,0 +1,4 @@ +dist/ +.mypy_cache/ +__pycache__/ +poetry.toml diff --git a/seed/pydantic/oauth-client-credentials-default/.inputs/config.json b/seed/pydantic/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..0bdc0b93fbb --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,30 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "pypi", + "registryUrl": "", + "packageName": "fern_oauth-client-credentials-default", + "usernameEnvironmentVariable": "", + "passwordEnvironmentVariable": "" + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/pydantic/oauth-client-credentials-default/.inputs/ir.json b/seed/pydantic/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..5b243c4c206 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1115 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/pydantic/oauth-client-credentials-default/.mock/definition/api.yml b/seed/pydantic/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/pydantic/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/pydantic/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/pydantic/oauth-client-credentials-default/.mock/fern.config.json b/seed/pydantic/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/pydantic/oauth-client-credentials-default/.mock/generators.yml b/seed/pydantic/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/pydantic/oauth-client-credentials-default/README.md b/seed/pydantic/oauth-client-credentials-default/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/pydantic/oauth-client-credentials-default/pyproject.toml b/seed/pydantic/oauth-client-credentials-default/pyproject.toml new file mode 100644 index 00000000000..cb78a51611f --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/pyproject.toml @@ -0,0 +1,30 @@ +[tool.poetry] +name = "fern_oauth-client-credentials-default" +version = "0.0.1" +description = "" +readme = "README.md" +authors = [] +packages = [ + { include = "seed/oauth_client_credentials_default", from = "src"} +] + +[tool.poetry.dependencies] +python = "^3.8" + +[tool.poetry.dev-dependencies] +mypy = "1.9.0" +pytest = "^7.4.0" +pytest-asyncio = "^0.23.5" +python-dateutil = "^2.9.0" + +[tool.pytest.ini_options] +testpaths = [ "tests" ] +asyncio_mode = "auto" + +[tool.mypy] +plugins = ["pydantic.mypy"] + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/seed/pydantic/oauth-client-credentials-default/snippet-templates.json b/seed/pydantic/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/pydantic/oauth-client-credentials-default/snippet.json b/seed/pydantic/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/__init__.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/__init__.py new file mode 100644 index 00000000000..c1750dcca66 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .resources import TokenResponse, auth + +__all__ = ["TokenResponse", "auth"] diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/__init__.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/__init__.py new file mode 100644 index 00000000000..b677880f4fe --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .datetime_utils import serialize_datetime +from .pydantic_utilities import pydantic_v1 + +__all__ = ["pydantic_v1", "serialize_datetime"] diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/datetime_utils.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/datetime_utils.py new file mode 100644 index 00000000000..7c9864a944c --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/datetime_utils.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt + + +def serialize_datetime(v: dt.datetime) -> str: + """ + Serialize a datetime including timezone info. + + Uses the timezone info provided if present, otherwise uses the current runtime's timezone info. + + UTC datetimes end in "Z" while all other timezones are represented as offset from UTC, e.g. +05:00. + """ + + def _serialize_zoned_datetime(v: dt.datetime) -> str: + if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None): + # UTC is a special case where we use "Z" at the end instead of "+00:00" + return v.isoformat().replace("+00:00", "Z") + else: + # Delegate to the typical +/- offset format + return v.isoformat() + + if v.tzinfo is not None: + return _serialize_zoned_datetime(v) + else: + local_tz = dt.datetime.now().astimezone().tzinfo + localized_dt = v.replace(tzinfo=local_tz) + return _serialize_zoned_datetime(localized_dt) diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/pydantic_utilities.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/pydantic_utilities.py new file mode 100644 index 00000000000..952b5f2a8a8 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/core/pydantic_utilities.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import pydantic + +IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") + +if IS_PYDANTIC_V2: + import pydantic.v1 as pydantic_v1 # type: ignore # nopycln: import +else: + import pydantic as pydantic_v1 # type: ignore # nopycln: import + +__all__ = ["pydantic_v1"] diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/py.typed b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/__init__.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/__init__.py new file mode 100644 index 00000000000..67b9ca3d89f --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from . import auth +from .auth import TokenResponse + +__all__ = ["TokenResponse", "auth"] diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/__init__.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/__init__.py new file mode 100644 index 00000000000..2ab0052fced --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .token_response import TokenResponse + +__all__ = ["TokenResponse"] diff --git a/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/token_response.py b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/token_response.py new file mode 100644 index 00000000000..299831a06d4 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/src/seed/oauth_client_credentials_default/resources/auth/token_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ...core.datetime_utils import serialize_datetime +from ...core.pydantic_utilities import pydantic_v1 + + +class TokenResponse(pydantic_v1.BaseModel): + """ + An OAuth token response. + """ + + access_token: str + expires_in: int + + def json(self, **kwargs: typing.Any) -> str: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().json(**kwargs_with_defaults) + + def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().dict(**kwargs_with_defaults) + + class Config: + extra = pydantic_v1.Extra.allow + json_encoders = {dt.datetime: serialize_datetime} diff --git a/seed/pydantic/oauth-client-credentials-default/tests/custom/test_client.py b/seed/pydantic/oauth-client-credentials-default/tests/custom/test_client.py new file mode 100644 index 00000000000..60a58e64c27 --- /dev/null +++ b/seed/pydantic/oauth-client-credentials-default/tests/custom/test_client.py @@ -0,0 +1,6 @@ +import pytest + +# Get started with writing tests with pytest at https://docs.pytest.org +@pytest.mark.skip(reason="Unimplemented") +def test_client() -> None: + assert True == True diff --git a/seed/python-sdk/oauth-client-credentials-default/.github/workflows/ci.yml b/seed/python-sdk/oauth-client-credentials-default/.github/workflows/ci.yml new file mode 100644 index 00000000000..13313993739 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: ci + +on: [push] +jobs: + compile: + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Compile + run: poetry run mypy . + test: + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Test + run: fern test --command "poetry run pytest -rP ." + + publish: + needs: [compile, test] + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Set up python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Bootstrap poetry + run: | + curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + - name: Install dependencies + run: poetry install + - name: Publish to pypi + run: | + poetry config repositories.remote + poetry --no-interaction -v publish --build --repository remote --username "$" --password "$" + env: + : ${{ secrets. }} + : ${{ secrets. }} diff --git a/seed/python-sdk/oauth-client-credentials-default/.gitignore b/seed/python-sdk/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..42cb863501e --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.gitignore @@ -0,0 +1,4 @@ +dist/ +.mypy_cache/ +__pycache__/ +poetry.toml diff --git a/seed/python-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/python-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..0bdc0b93fbb --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,30 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "pypi", + "registryUrl": "", + "packageName": "fern_oauth-client-credentials-default", + "usernameEnvironmentVariable": "", + "passwordEnvironmentVariable": "" + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/python-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..5e28ba4c46d --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1143 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": "endpoint_auth.getToken", + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/.mock/definition/api.yml b/seed/python-sdk/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/python-sdk/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/.mock/fern.config.json b/seed/python-sdk/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/.mock/generators.yml b/seed/python-sdk/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/python-sdk/oauth-client-credentials-default/README.md b/seed/python-sdk/oauth-client-credentials-default/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/python-sdk/oauth-client-credentials-default/pyproject.toml b/seed/python-sdk/oauth-client-credentials-default/pyproject.toml new file mode 100644 index 00000000000..605c38f5fe8 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/pyproject.toml @@ -0,0 +1,33 @@ +[tool.poetry] +name = "fern_oauth-client-credentials-default" +version = "0.0.1" +description = "" +readme = "README.md" +authors = [] +packages = [ + { include = "seed", from = "src"} +] + +[tool.poetry.dependencies] +python = "^3.8" +httpx = ">=0.21.2" +pydantic = ">= 1.9.2" +typing_extensions = ">= 4.0.0" + +[tool.poetry.dev-dependencies] +mypy = "1.9.0" +pytest = "^7.4.0" +pytest-asyncio = "^0.23.5" +python-dateutil = "^2.9.0" + +[tool.pytest.ini_options] +testpaths = [ "tests" ] +asyncio_mode = "auto" + +[tool.mypy] +plugins = ["pydantic.mypy"] + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/seed/python-sdk/oauth-client-credentials-default/snippet-templates.json b/seed/python-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..365f502205d --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/snippet-templates.json @@ -0,0 +1,105 @@ +[ + { + "sdk": { + "package": "fern_oauth-client-credentials-default", + "version": "0.0.1", + "type": "python" + }, + "endpointId": { + "path": "/token", + "method": "POST" + }, + "snippetTemplate": { + "clientInstantiation": "from seed.client import SeedOauthClientCredentialsDefault\n\nclient = SeedOauthClientCredentialsDefault(\n base_url=\"https://yourhost.com/path/to/api\",\n client_id=\"YOUR_CLIENT_ID\",\n client_secret=\"YOUR_CLIENT_SECRET\",\n)", + "functionInvocation": { + "imports": [], + "isOptional": true, + "templateString": "client.auth.get_token(\n\t$FERN_INPUT\n)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "client_id=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "client_id", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "client_secret=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "client_secret", + "type": "payload" + } + ], + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t", + "type": "generic" + }, + "type": "v1" + }, + "additionalTemplates": { + "async": { + "clientInstantiation": "from seed.client import AsyncSeedOauthClientCredentialsDefault\n\nclient = AsyncSeedOauthClientCredentialsDefault(\n base_url=\"https://yourhost.com/path/to/api\",\n client_id=\"YOUR_CLIENT_ID\",\n client_secret=\"YOUR_CLIENT_SECRET\",\n)", + "functionInvocation": { + "imports": [], + "isOptional": true, + "templateString": "await client.auth.get_token(\n\t$FERN_INPUT\n)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "client_id=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "client_id", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "client_secret=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "client_secret", + "type": "payload" + } + ], + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t", + "type": "generic" + }, + "type": "v1" + } + } + } +] \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/snippet.json b/seed/python-sdk/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..9d67e384925 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/snippet.json @@ -0,0 +1,16 @@ +{ + "types": {}, + "endpoints": [ + { + "id": { + "path": "/token", + "method": "POST" + }, + "snippet": { + "sync_client": "from seed.client import SeedOauthClientCredentialsDefault\n\nclient = SeedOauthClientCredentialsDefault(\n base_url=\"https://yourhost.com/path/to/api\",\n client_id=\"YOUR_CLIENT_ID\",\n client_secret=\"YOUR_CLIENT_SECRET\",\n)\nclient.auth.get_token(\n client_id=\"string\",\n client_secret=\"string\",\n)\n", + "async_client": "from seed.client import AsyncSeedOauthClientCredentialsDefault\n\nclient = AsyncSeedOauthClientCredentialsDefault(\n base_url=\"https://yourhost.com/path/to/api\",\n client_id=\"YOUR_CLIENT_ID\",\n client_secret=\"YOUR_CLIENT_SECRET\",\n)\nawait client.auth.get_token(\n client_id=\"string\",\n client_secret=\"string\",\n)\n", + "type": "python" + } + } + ] +} \ No newline at end of file diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/__init__.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/__init__.py new file mode 100644 index 00000000000..4a009e5fcbb --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/__init__.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +from . import auth +from .auth import TokenResponse +from .version import __version__ + +__all__ = ["TokenResponse", "__version__", "auth"] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/__init__.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/__init__.py new file mode 100644 index 00000000000..3d9382fea51 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import TokenResponse + +__all__ = ["TokenResponse"] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/client.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/client.py new file mode 100644 index 00000000000..f19e7a35d7b --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/client.py @@ -0,0 +1,164 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +import urllib.parse +from json.decoder import JSONDecodeError + +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import pydantic_v1 +from ..core.remove_none_from_dict import remove_none_from_dict +from ..core.request_options import RequestOptions +from .types.token_response import TokenResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class AuthClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_token( + self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None + ) -> TokenResponse: + """ + Parameters + ---------- + client_id : str + + client_secret : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TokenResponse + + Examples + -------- + from seed.client import SeedOauthClientCredentialsDefault + + client = SeedOauthClientCredentialsDefault( + base_url="https://yourhost.com/path/to/api", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + client.auth.get_token( + client_id="string", + client_secret="string", + ) + """ + _response = self._client_wrapper.httpx_client.request( + method="POST", + url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token"), + params=jsonable_encoder( + request_options.get("additional_query_parameters") if request_options is not None else None + ), + json=jsonable_encoder( + {"client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials"} + ) + if request_options is None or request_options.get("additional_body_parameters") is None + else { + **jsonable_encoder( + {"client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials"} + ), + **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))), + }, + headers=jsonable_encoder( + remove_none_from_dict( + { + **self._client_wrapper.get_headers(), + **(request_options.get("additional_headers", {}) if request_options is not None else {}), + } + ) + ), + timeout=request_options.get("timeout_in_seconds") + if request_options is not None and request_options.get("timeout_in_seconds") is not None + else self._client_wrapper.get_timeout(), + retries=0, + max_retries=request_options.get("max_retries") if request_options is not None else 0, # type: ignore + ) + if 200 <= _response.status_code < 300: + return pydantic_v1.parse_obj_as(TokenResponse, _response.json()) # type: ignore + try: + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncAuthClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_token( + self, *, client_id: str, client_secret: str, request_options: typing.Optional[RequestOptions] = None + ) -> TokenResponse: + """ + Parameters + ---------- + client_id : str + + client_secret : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + TokenResponse + + Examples + -------- + from seed.client import AsyncSeedOauthClientCredentialsDefault + + client = AsyncSeedOauthClientCredentialsDefault( + base_url="https://yourhost.com/path/to/api", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + await client.auth.get_token( + client_id="string", + client_secret="string", + ) + """ + _response = await self._client_wrapper.httpx_client.request( + method="POST", + url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token"), + params=jsonable_encoder( + request_options.get("additional_query_parameters") if request_options is not None else None + ), + json=jsonable_encoder( + {"client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials"} + ) + if request_options is None or request_options.get("additional_body_parameters") is None + else { + **jsonable_encoder( + {"client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials"} + ), + **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))), + }, + headers=jsonable_encoder( + remove_none_from_dict( + { + **self._client_wrapper.get_headers(), + **(request_options.get("additional_headers", {}) if request_options is not None else {}), + } + ) + ), + timeout=request_options.get("timeout_in_seconds") + if request_options is not None and request_options.get("timeout_in_seconds") is not None + else self._client_wrapper.get_timeout(), + retries=0, + max_retries=request_options.get("max_retries") if request_options is not None else 0, # type: ignore + ) + if 200 <= _response.status_code < 300: + return pydantic_v1.parse_obj_as(TokenResponse, _response.json()) # type: ignore + try: + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/__init__.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/__init__.py new file mode 100644 index 00000000000..2ab0052fced --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .token_response import TokenResponse + +__all__ = ["TokenResponse"] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/token_response.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/token_response.py new file mode 100644 index 00000000000..1933aa1d22a --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/auth/types/token_response.py @@ -0,0 +1,30 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ...core.datetime_utils import serialize_datetime +from ...core.pydantic_utilities import pydantic_v1 + + +class TokenResponse(pydantic_v1.BaseModel): + """ + An OAuth token response. + """ + + access_token: str + expires_in: int + + def json(self, **kwargs: typing.Any) -> str: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().json(**kwargs_with_defaults) + + def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: + kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs} + return super().dict(**kwargs_with_defaults) + + class Config: + frozen = True + smart_union = True + extra = pydantic_v1.Extra.allow + json_encoders = {dt.datetime: serialize_datetime} diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/client.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/client.py new file mode 100644 index 00000000000..594cad79159 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/client.py @@ -0,0 +1,141 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import httpx + +from .auth.client import AsyncAuthClient, AuthClient +from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from .core.oauth_token_provider import OAuthTokenProvider + + +class SeedOauthClientCredentialsDefault: + """ + Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propogate to these functions. + + Parameters + ---------- + base_url : str + The base url to use for requests from the client. + + client_id : str + client_secret : str + timeout : typing.Optional[float] + The timeout to be used, in seconds, for requests by default the timeout is 60 seconds, unless a custom httpx client is used, in which case a default is not set. + + follow_redirects : typing.Optional[bool] + Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in. + + httpx_client : typing.Optional[httpx.Client] + The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration. + + Examples + -------- + from seed.client import SeedOauthClientCredentialsDefault + + client = SeedOauthClientCredentialsDefault( + base_url="https://yourhost.com/path/to/api", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + """ + + def __init__( + self, + *, + base_url: str, + client_id: str, + client_secret: str, + timeout: typing.Optional[float] = None, + follow_redirects: typing.Optional[bool] = True, + httpx_client: typing.Optional[httpx.Client] = None + ): + _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None + oauth_token_provider = OAuthTokenProvider( + client_id=client_id, + client_secret=client_secret, + client_wrapper=SyncClientWrapper( + base_url=base_url, + httpx_client=httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects) + if follow_redirects is not None + else httpx.Client(timeout=_defaulted_timeout), + timeout=_defaulted_timeout, + ), + ) + self._client_wrapper = SyncClientWrapper( + base_url=base_url, + token=oauth_token_provider.get_token, + httpx_client=httpx_client + if httpx_client is not None + else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects) + if follow_redirects is not None + else httpx.Client(timeout=_defaulted_timeout), + timeout=_defaulted_timeout, + ) + self.auth = AuthClient(client_wrapper=self._client_wrapper) + + +class AsyncSeedOauthClientCredentialsDefault: + """ + Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propogate to these functions. + + Parameters + ---------- + base_url : str + The base url to use for requests from the client. + + client_id : str + client_secret : str + timeout : typing.Optional[float] + The timeout to be used, in seconds, for requests by default the timeout is 60 seconds, unless a custom httpx client is used, in which case a default is not set. + + follow_redirects : typing.Optional[bool] + Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in. + + httpx_client : typing.Optional[httpx.AsyncClient] + The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration. + + Examples + -------- + from seed.client import AsyncSeedOauthClientCredentialsDefault + + client = AsyncSeedOauthClientCredentialsDefault( + base_url="https://yourhost.com/path/to/api", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + """ + + def __init__( + self, + *, + base_url: str, + client_id: str, + client_secret: str, + timeout: typing.Optional[float] = None, + follow_redirects: typing.Optional[bool] = True, + httpx_client: typing.Optional[httpx.AsyncClient] = None + ): + _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None + oauth_token_provider = OAuthTokenProvider( + client_id=client_id, + client_secret=client_secret, + client_wrapper=SyncClientWrapper( + base_url=base_url, + httpx_client=httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects) + if follow_redirects is not None + else httpx.Client(timeout=_defaulted_timeout), + timeout=_defaulted_timeout, + ), + ) + self._client_wrapper = AsyncClientWrapper( + base_url=base_url, + token=oauth_token_provider.get_token, + httpx_client=httpx_client + if httpx_client is not None + else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects) + if follow_redirects is not None + else httpx.AsyncClient(timeout=_defaulted_timeout), + timeout=_defaulted_timeout, + ) + self.auth = AsyncAuthClient(client_wrapper=self._client_wrapper) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/__init__.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/__init__.py new file mode 100644 index 00000000000..78a7f80fb35 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/__init__.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from .api_error import ApiError +from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper +from .datetime_utils import serialize_datetime +from .file import File, convert_file_dict_to_httpx_tuples +from .http_client import AsyncHttpClient, HttpClient +from .jsonable_encoder import jsonable_encoder +from .pydantic_utilities import pydantic_v1 +from .remove_none_from_dict import remove_none_from_dict +from .request_options import RequestOptions + +__all__ = [ + "ApiError", + "AsyncClientWrapper", + "AsyncHttpClient", + "BaseClientWrapper", + "File", + "HttpClient", + "RequestOptions", + "SyncClientWrapper", + "convert_file_dict_to_httpx_tuples", + "jsonable_encoder", + "pydantic_v1", + "remove_none_from_dict", + "serialize_datetime", +] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/api_error.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/api_error.py new file mode 100644 index 00000000000..2e9fc5431cd --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/api_error.py @@ -0,0 +1,15 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + + +class ApiError(Exception): + status_code: typing.Optional[int] + body: typing.Any + + def __init__(self, *, status_code: typing.Optional[int] = None, body: typing.Any = None): + self.status_code = status_code + self.body = body + + def __str__(self) -> str: + return f"status_code: {self.status_code}, body: {self.body}" diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/client_wrapper.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/client_wrapper.py new file mode 100644 index 00000000000..abaefdd0ba7 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/client_wrapper.py @@ -0,0 +1,69 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import httpx + +from .http_client import AsyncHttpClient, HttpClient + + +class BaseClientWrapper: + def __init__( + self, + *, + token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + base_url: str, + timeout: typing.Optional[float] = None, + ): + self._token = token + self._base_url = base_url + self._timeout = timeout + + def get_headers(self) -> typing.Dict[str, str]: + headers: typing.Dict[str, str] = { + "X-Fern-Language": "Python", + "X-Fern-SDK-Name": "fern_oauth-client-credentials-default", + "X-Fern-SDK-Version": "0.0.1", + } + token = self._get_token() + if token is not None: + headers["Authorization"] = f"Bearer {token}" + return headers + + def _get_token(self) -> typing.Optional[str]: + if isinstance(self._token, str) or self._token is None: + return self._token + else: + return self._token() + + def get_base_url(self) -> str: + return self._base_url + + def get_timeout(self) -> typing.Optional[float]: + return self._timeout + + +class SyncClientWrapper(BaseClientWrapper): + def __init__( + self, + *, + token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + base_url: str, + timeout: typing.Optional[float] = None, + httpx_client: httpx.Client, + ): + super().__init__(token=token, base_url=base_url, timeout=timeout) + self.httpx_client = HttpClient(httpx_client=httpx_client) + + +class AsyncClientWrapper(BaseClientWrapper): + def __init__( + self, + *, + token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + base_url: str, + timeout: typing.Optional[float] = None, + httpx_client: httpx.AsyncClient, + ): + super().__init__(token=token, base_url=base_url, timeout=timeout) + self.httpx_client = AsyncHttpClient(httpx_client=httpx_client) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/datetime_utils.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/datetime_utils.py new file mode 100644 index 00000000000..7c9864a944c --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/datetime_utils.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt + + +def serialize_datetime(v: dt.datetime) -> str: + """ + Serialize a datetime including timezone info. + + Uses the timezone info provided if present, otherwise uses the current runtime's timezone info. + + UTC datetimes end in "Z" while all other timezones are represented as offset from UTC, e.g. +05:00. + """ + + def _serialize_zoned_datetime(v: dt.datetime) -> str: + if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None): + # UTC is a special case where we use "Z" at the end instead of "+00:00" + return v.isoformat().replace("+00:00", "Z") + else: + # Delegate to the typical +/- offset format + return v.isoformat() + + if v.tzinfo is not None: + return _serialize_zoned_datetime(v) + else: + local_tz = dt.datetime.now().astimezone().tzinfo + localized_dt = v.replace(tzinfo=local_tz) + return _serialize_zoned_datetime(localized_dt) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/file.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/file.py new file mode 100644 index 00000000000..cb0d40bbbf3 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/file.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +# File typing inspired by the flexibility of types within the httpx library +# https://github.com/encode/httpx/blob/master/httpx/_types.py +FileContent = typing.Union[typing.IO[bytes], bytes, str] +File = typing.Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + typing.Tuple[typing.Optional[str], FileContent], + # (filename, file (or bytes), content_type) + typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str]], + # (filename, file (or bytes), content_type, headers) + typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str], typing.Mapping[str, str]], +] + + +def convert_file_dict_to_httpx_tuples( + d: typing.Dict[str, typing.Union[File, typing.List[File]]] +) -> typing.List[typing.Tuple[str, File]]: + """ + The format we use is a list of tuples, where the first element is the + name of the file and the second is the file object. Typically HTTPX wants + a dict, but to be able to send lists of files, you have to use the list + approach (which also works for non-lists) + https://github.com/encode/httpx/pull/1032 + """ + + httpx_tuples = [] + for key, file_like in d.items(): + if isinstance(file_like, list): + for file_like_item in file_like: + httpx_tuples.append((key, file_like_item)) + else: + httpx_tuples.append((key, file_like)) + return httpx_tuples diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/http_client.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/http_client.py new file mode 100644 index 00000000000..4e6877df257 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/http_client.py @@ -0,0 +1,130 @@ +# This file was auto-generated by Fern from our API Definition. + +import asyncio +import email.utils +import re +import time +import typing +from contextlib import asynccontextmanager, contextmanager +from functools import wraps +from random import random + +import httpx + +INITIAL_RETRY_DELAY_SECONDS = 0.5 +MAX_RETRY_DELAY_SECONDS = 10 +MAX_RETRY_DELAY_SECONDS_FROM_HEADER = 30 + + +def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]: + """ + This function parses the `Retry-After` header in a HTTP response and returns the number of seconds to wait. + + Inspired by the urllib3 retry implementation. + """ + retry_after_ms = response_headers.get("retry-after-ms") + if retry_after_ms is not None: + try: + return int(retry_after_ms) / 1000 if retry_after_ms > 0 else 0 + except Exception: + pass + + retry_after = response_headers.get("retry-after") + if retry_after is None: + return None + + # Attempt to parse the header as an int. + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = float(retry_after) + # Fallback to parsing it as a date. + else: + retry_date_tuple = email.utils.parsedate_tz(retry_after) + if retry_date_tuple is None: + return None + if retry_date_tuple[9] is None: # Python 2 + # Assume UTC if no timezone was specified + # On Python2.7, parsedate_tz returns None for a timezone offset + # instead of 0 if no timezone is given, where mktime_tz treats + # a None timezone offset as local time. + retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:] + + retry_date = email.utils.mktime_tz(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + +def _retry_timeout(response: httpx.Response, retries: int) -> float: + """ + Determine the amount of time to wait before retrying a request. + This function begins by trying to parse a retry-after header from the response, and then proceeds to use exponential backoff + with a jitter to determine the number of seconds to wait. + """ + + # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + retry_after = _parse_retry_after(response.headers) + if retry_after is not None and retry_after <= MAX_RETRY_DELAY_SECONDS_FROM_HEADER: + return retry_after + + # Apply exponential backoff, capped at MAX_RETRY_DELAY_SECONDS. + retry_delay = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS) + + # Add a randomness / jitter to the retry delay to avoid overwhelming the server with retries. + timeout = retry_delay * (1 - 0.25 * random()) + return timeout if timeout >= 0 else 0 + + +def _should_retry(response: httpx.Response) -> bool: + retriable_400s = [429, 408, 409] + return response.status_code >= 500 or response.status_code in retriable_400s + + +class HttpClient: + def __init__(self, *, httpx_client: httpx.Client): + self.httpx_client = httpx_client + + # Ensure that the signature of the `request` method is the same as the `httpx.Client.request` method + @wraps(httpx.Client.request) + def request( + self, *args: typing.Any, max_retries: int = 0, retries: int = 0, **kwargs: typing.Any + ) -> httpx.Response: + response = self.httpx_client.request(*args, **kwargs) + if _should_retry(response=response): + if max_retries > retries: + time.sleep(_retry_timeout(response=response, retries=retries)) + return self.request(max_retries=max_retries, retries=retries + 1, *args, **kwargs) + return response + + @wraps(httpx.Client.stream) + @contextmanager + def stream(self, *args: typing.Any, max_retries: int = 0, retries: int = 0, **kwargs: typing.Any) -> typing.Any: + with self.httpx_client.stream(*args, **kwargs) as stream: + yield stream + + +class AsyncHttpClient: + def __init__(self, *, httpx_client: httpx.AsyncClient): + self.httpx_client = httpx_client + + # Ensure that the signature of the `request` method is the same as the `httpx.Client.request` method + @wraps(httpx.AsyncClient.request) + async def request( + self, *args: typing.Any, max_retries: int = 0, retries: int = 0, **kwargs: typing.Any + ) -> httpx.Response: + response = await self.httpx_client.request(*args, **kwargs) + if _should_retry(response=response): + if max_retries > retries: + await asyncio.sleep(_retry_timeout(response=response, retries=retries)) + return await self.request(max_retries=max_retries, retries=retries + 1, *args, **kwargs) + return response + + @wraps(httpx.AsyncClient.stream) + @asynccontextmanager + async def stream( + self, *args: typing.Any, max_retries: int = 0, retries: int = 0, **kwargs: typing.Any + ) -> typing.Any: + async with self.httpx_client.stream(*args, **kwargs) as stream: + yield stream diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/jsonable_encoder.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/jsonable_encoder.py new file mode 100644 index 00000000000..7f482732638 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/jsonable_encoder.py @@ -0,0 +1,99 @@ +# This file was auto-generated by Fern from our API Definition. + +""" +jsonable_encoder converts a Python object to a JSON-friendly dict +(e.g. datetimes to strings, Pydantic models to dicts). + +Taken from FastAPI, and made a bit simpler +https://github.com/tiangolo/fastapi/blob/master/fastapi/encoders.py +""" + +import dataclasses +import datetime as dt +from collections import defaultdict +from enum import Enum +from pathlib import PurePath +from types import GeneratorType +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union + +from .datetime_utils import serialize_datetime +from .pydantic_utilities import pydantic_v1 + +SetIntStr = Set[Union[int, str]] +DictIntStrAny = Dict[Union[int, str], Any] + + +def generate_encoders_by_class_tuples( + type_encoder_map: Dict[Any, Callable[[Any], Any]] +) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]: + encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(tuple) + for type_, encoder in type_encoder_map.items(): + encoders_by_class_tuples[encoder] += (type_,) + return encoders_by_class_tuples + + +encoders_by_class_tuples = generate_encoders_by_class_tuples(pydantic_v1.json.ENCODERS_BY_TYPE) + + +def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any: + custom_encoder = custom_encoder or {} + if custom_encoder: + if type(obj) in custom_encoder: + return custom_encoder[type(obj)](obj) + else: + for encoder_type, encoder_instance in custom_encoder.items(): + if isinstance(obj, encoder_type): + return encoder_instance(obj) + if isinstance(obj, pydantic_v1.BaseModel): + encoder = getattr(obj.__config__, "json_encoders", {}) + if custom_encoder: + encoder.update(custom_encoder) + obj_dict = obj.dict(by_alias=True) + if "__root__" in obj_dict: + obj_dict = obj_dict["__root__"] + return jsonable_encoder(obj_dict, custom_encoder=encoder) + if dataclasses.is_dataclass(obj): + obj_dict = dataclasses.asdict(obj) + return jsonable_encoder(obj_dict, custom_encoder=custom_encoder) + if isinstance(obj, Enum): + return obj.value + if isinstance(obj, PurePath): + return str(obj) + if isinstance(obj, (str, int, float, type(None))): + return obj + if isinstance(obj, dt.datetime): + return serialize_datetime(obj) + if isinstance(obj, dt.date): + return str(obj) + if isinstance(obj, dict): + encoded_dict = {} + allowed_keys = set(obj.keys()) + for key, value in obj.items(): + if key in allowed_keys: + encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder) + encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder) + encoded_dict[encoded_key] = encoded_value + return encoded_dict + if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)): + encoded_list = [] + for item in obj: + encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder)) + return encoded_list + + if type(obj) in pydantic_v1.json.ENCODERS_BY_TYPE: + return pydantic_v1.json.ENCODERS_BY_TYPE[type(obj)](obj) + for encoder, classes_tuple in encoders_by_class_tuples.items(): + if isinstance(obj, classes_tuple): + return encoder(obj) + + try: + data = dict(obj) + except Exception as e: + errors: List[Exception] = [] + errors.append(e) + try: + data = vars(obj) + except Exception as e: + errors.append(e) + raise ValueError(errors) from e + return jsonable_encoder(data, custom_encoder=custom_encoder) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/oauth_token_provider.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/oauth_token_provider.py new file mode 100644 index 00000000000..abde7aae67f --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/oauth_token_provider.py @@ -0,0 +1,30 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..auth.client import AuthClient +from .client_wrapper import SyncClientWrapper + + +class OAuthTokenProvider: + BUFFER_IN_MINUTES = 2 + + def __init__(self, *, client_id: str, client_secret: str, client_wrapper: SyncClientWrapper): + self._client_id = client_id + self._client_secret = client_secret + self._access_token: typing.Optional[str] = None + self._auth_client = AuthClient(client_wrapper=client_wrapper) + + def get_token(self) -> str: + if self._access_token and self._expires_at > dt.datetime.now(): + return self._access_token + return self._refresh() + + def _refresh(self) -> str: + token_response = self._auth_client.get_token(client_id=self._client_id, client_secret=self._client_secret) + self._access_token = token_response.access_token + return self._access_token + + def _get_expires_at(self, *, expires_in_seconds: int, buffer_in_minutes: int): + return dt.datetime.now() + dt.timedelta(seconds=expires_in_seconds) - dt.timedelta(minutes=buffer_in_minutes) diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/pydantic_utilities.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/pydantic_utilities.py new file mode 100644 index 00000000000..952b5f2a8a8 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/pydantic_utilities.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import pydantic + +IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") + +if IS_PYDANTIC_V2: + import pydantic.v1 as pydantic_v1 # type: ignore # nopycln: import +else: + import pydantic as pydantic_v1 # type: ignore # nopycln: import + +__all__ = ["pydantic_v1"] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/remove_none_from_dict.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/remove_none_from_dict.py new file mode 100644 index 00000000000..2da30f71337 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/remove_none_from_dict.py @@ -0,0 +1,11 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import Any, Dict, Optional + + +def remove_none_from_dict(original: Dict[str, Optional[Any]]) -> Dict[str, Any]: + new: Dict[str, Any] = {} + for key, value in original.items(): + if value is not None: + new[key] = value + return new diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/core/request_options.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/request_options.py new file mode 100644 index 00000000000..cd6f27a7e9b --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/core/request_options.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +try: + from typing import NotRequired # type: ignore +except ImportError: + from typing_extensions import NotRequired # type: ignore + + +class RequestOptions(typing.TypedDict): + """ + Additional options for request-specific configuration when calling APIs via the SDK. + This is used primarily as an optional final parameter for service functions. + + Attributes: + - timeout_in_seconds: int. The number of seconds to await an API call before timing out. + + - max_retries: int. The max number of retries to attempt if the API call fails. + + - additional_headers: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's header dict + + - additional_query_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's query parameters dict + + - additional_body_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's body parameters dict + """ + + timeout_in_seconds: NotRequired[int] + max_retries: NotRequired[int] + additional_headers: NotRequired[typing.Dict[str, typing.Any]] + additional_query_parameters: NotRequired[typing.Dict[str, typing.Any]] + additional_body_parameters: NotRequired[typing.Dict[str, typing.Any]] diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/py.typed b/seed/python-sdk/oauth-client-credentials-default/src/seed/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/python-sdk/oauth-client-credentials-default/src/seed/version.py b/seed/python-sdk/oauth-client-credentials-default/src/seed/version.py new file mode 100644 index 00000000000..42124c75b97 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/src/seed/version.py @@ -0,0 +1,4 @@ + +from importlib import metadata + +__version__ = metadata.version("fern_oauth-client-credentials-default") diff --git a/seed/python-sdk/oauth-client-credentials-default/tests/custom/test_client.py b/seed/python-sdk/oauth-client-credentials-default/tests/custom/test_client.py new file mode 100644 index 00000000000..60a58e64c27 --- /dev/null +++ b/seed/python-sdk/oauth-client-credentials-default/tests/custom/test_client.py @@ -0,0 +1,6 @@ +import pytest + +# Get started with writing tests with pytest at https://docs.pytest.org +@pytest.mark.skip(reason="Unimplemented") +def test_client() -> None: + assert True == True diff --git a/seed/ruby-model/oauth-client-credentials-default/.inputs/config.json b/seed/ruby-model/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..cd6b9b51711 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,20 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/ruby-model/oauth-client-credentials-default/.inputs/ir.json b/seed/ruby-model/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..59adde187d0 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,694 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/ruby-model/oauth-client-credentials-default/.mock/definition/api.yml b/seed/ruby-model/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/ruby-model/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/ruby-model/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/ruby-model/oauth-client-credentials-default/.mock/fern.config.json b/seed/ruby-model/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/ruby-model/oauth-client-credentials-default/.mock/generators.yml b/seed/ruby-model/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/ruby-model/oauth-client-credentials-default/.rubocop.yml b/seed/ruby-model/oauth-client-credentials-default/.rubocop.yml new file mode 100644 index 00000000000..c1d2344d6e6 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/.rubocop.yml @@ -0,0 +1,36 @@ +AllCops: + TargetRubyVersion: 2.7 + +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + Enabled: true + EnforcedStyle: double_quotes + +Layout/FirstHashElementLineBreak: + Enabled: true + +Layout/MultilineHashKeyLineBreaks: + Enabled: true + +# Generated files may be more complex than standard, disable +# these rules for now as a known limitation. +Metrics/ParameterLists: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false diff --git a/seed/ruby-model/oauth-client-credentials-default/Gemfile b/seed/ruby-model/oauth-client-credentials-default/Gemfile new file mode 100644 index 00000000000..49bd9cd0173 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +gem "minitest", "~> 5.0" +gem "rake", "~> 13.0" +gem "rubocop", "~> 1.21" diff --git a/seed/ruby-model/oauth-client-credentials-default/Rakefile b/seed/ruby-model/oauth-client-credentials-default/Rakefile new file mode 100644 index 00000000000..2bdbce0cf2c --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/Rakefile @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "rake/testtask" +require "rubocop/rake_task" + +task default: %i[test rubocop] + +Rake::TestTask.new do |t| + t.pattern = "./test/**/test_*.rb" +end + +RuboCop::RakeTask.new diff --git a/seed/ruby-model/oauth-client-credentials-default/lib/gemconfig.rb b/seed/ruby-model/oauth-client-credentials-default/lib/gemconfig.rb new file mode 100644 index 00000000000..65720bd53af --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/lib/gemconfig.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module SeedOauthClientCredentialsDefaultClient + module Gemconfig + VERSION = "" + AUTHORS = [""].freeze + EMAIL = "" + SUMMARY = "" + DESCRIPTION = "" + HOMEPAGE = "https://github.com/REPO/URL" + SOURCE_CODE_URI = "https://github.com/REPO/URL" + CHANGELOG_URI = "https://github.com/REPO/URL/blob/master/CHANGELOG.md" + end +end diff --git a/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client.rb b/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client.rb new file mode 100644 index 00000000000..a029ac56011 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative "seed_oauth_client_credentials_default_client/auth/types/token_response" diff --git a/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client/auth/types/token_response.rb b/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client/auth/types/token_response.rb new file mode 100644 index 00000000000..0545f83ec93 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/lib/seed_oauth_client_credentials_default_client/auth/types/token_response.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "ostruct" +require "json" + +module SeedOauthClientCredentialsDefaultClient + class Auth + # An OAuth token response. + class TokenResponse + # @return [String] + attr_reader :access_token + # @return [Integer] + attr_reader :expires_in + # @return [OpenStruct] Additional properties unmapped to the current class definition + attr_reader :additional_properties + # @return [Object] + attr_reader :_field_set + protected :_field_set + + OMIT = Object.new + + # @param access_token [String] + # @param expires_in [Integer] + # @param additional_properties [OpenStruct] Additional properties unmapped to the current class definition + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def initialize(access_token:, expires_in:, additional_properties: nil) + @access_token = access_token + @expires_in = expires_in + @additional_properties = additional_properties + @_field_set = { "access_token": access_token, "expires_in": expires_in } + end + + # Deserialize a JSON object to an instance of TokenResponse + # + # @param json_object [String] + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def self.from_json(json_object:) + struct = JSON.parse(json_object, object_class: OpenStruct) + access_token = struct["access_token"] + expires_in = struct["expires_in"] + new( + access_token: access_token, + expires_in: expires_in, + additional_properties: struct + ) + end + + # Serialize an instance of TokenResponse to a JSON object + # + # @return [String] + def to_json(*_args) + @_field_set&.to_json + end + + # Leveraged for Union-type generation, validate_raw attempts to parse the given + # hash and check each fields type against the current object's property + # definitions. + # + # @param obj [Object] + # @return [Void] + def self.validate_raw(obj:) + obj.access_token.is_a?(String) != false || raise("Passed value for field obj.access_token is not the expected type, validation failed.") + obj.expires_in.is_a?(Integer) != false || raise("Passed value for field obj.expires_in is not the expected type, validation failed.") + end + end + end +end diff --git a/seed/ruby-model/oauth-client-credentials-default/seed_oauth_client_credentials_default_client.gemspec b/seed/ruby-model/oauth-client-credentials-default/seed_oauth_client_credentials_default_client.gemspec new file mode 100644 index 00000000000..5b08af4995b --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/seed_oauth_client_credentials_default_client.gemspec @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require_relative "lib/gemconfig" + +Gem::Specification.new do |spec| + spec.name = "seed_oauth_client_credentials_default_client" + spec.version = SeedOauthClientCredentialsDefaultClient::Gemconfig::VERSION + spec.authors = SeedOauthClientCredentialsDefaultClient::Gemconfig::AUTHORS + spec.email = SeedOauthClientCredentialsDefaultClient::Gemconfig::EMAIL + spec.summary = SeedOauthClientCredentialsDefaultClient::Gemconfig::SUMMARY + spec.description = SeedOauthClientCredentialsDefaultClient::Gemconfig::DESCRIPTION + spec.homepage = SeedOauthClientCredentialsDefaultClient::Gemconfig::HOMEPAGE + spec.required_ruby_version = ">= 2.7.0" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = SeedOauthClientCredentialsDefaultClient::Gemconfig::SOURCE_CODE_URI + spec.metadata["changelog_uri"] = SeedOauthClientCredentialsDefaultClient::Gemconfig::CHANGELOG_URI + spec.files = Dir.glob("lib/**/*") + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] +end diff --git a/seed/ruby-model/oauth-client-credentials-default/snippet-templates.json b/seed/ruby-model/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ruby-model/oauth-client-credentials-default/snippet.json b/seed/ruby-model/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ruby-model/oauth-client-credentials-default/test/test_helper.rb b/seed/ruby-model/oauth-client-credentials-default/test/test_helper.rb new file mode 100644 index 00000000000..3cf1d5fc2dd --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/test/test_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) + +require "minitest/autorun" +require "seed_oauth_client_credentials_default_client" diff --git a/seed/ruby-model/oauth-client-credentials-default/test/test_seed_oauth_client_credentials_default_client.rb b/seed/ruby-model/oauth-client-credentials-default/test/test_seed_oauth_client_credentials_default_client.rb new file mode 100644 index 00000000000..e373f4a7981 --- /dev/null +++ b/seed/ruby-model/oauth-client-credentials-default/test/test_seed_oauth_client_credentials_default_client.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require_relative "test_helper" +require "seed_oauth_client_credentials_default_client" + +# Basic SeedOauthClientCredentialsDefaultClient tests +class TestSeedOauthClientCredentialsDefaultClient < Minitest::Test + def test_function + # SeedOauthClientCredentialsDefaultClient::Client.new + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.github/workflows/publish.yml b/seed/ruby-sdk/oauth-client-credentials-default/.github/workflows/publish.yml new file mode 100644 index 00000000000..4bfa01fe7a1 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.github/workflows/publish.yml @@ -0,0 +1,26 @@ +name: Publish + +on: [push] +jobs: + publish: + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + bundler-cache: true + + - name: Test gem + run: bundle install && bundle exec rake test + + - name: Build and Push Gem + env: + GEM_HOST_API_KEY: ${{ secrets. }} + run: | + gem build fern_oauth_client_credentials_default.gemspec + + gem push fern_oauth_client_credentials_default-*.gem --host diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.gitignore b/seed/ruby-sdk/oauth-client-credentials-default/.gitignore new file mode 100644 index 00000000000..a97c182a2e1 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.gitignore @@ -0,0 +1,10 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +*.gem +.env diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/ruby-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..e869033bc4b --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,29 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "rubygems", + "registryUrl": "", + "packageName": "fern_oauth-client-credentials-default", + "apiKeyEnvironmentVariable": "" + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/ruby-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..59adde187d0 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,694 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "bearer", + "token": { + "originalName": "token", + "camelCase": { + "unsafeName": "token", + "safeName": "token" + }, + "pascalCase": { + "unsafeName": "Token", + "safeName": "Token" + }, + "snakeCase": { + "unsafeName": "token", + "safeName": "token" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN", + "safeName": "TOKEN" + } + }, + "tokenEnvVar": null, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ] + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "method": "POST", + "headers": [], + "baseUrl": null, + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "errors": [], + "auth": false, + "idempotent": false, + "examples": [], + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/api.yml b/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.mock/fern.config.json b/seed/ruby-sdk/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.mock/generators.yml b/seed/ruby-sdk/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/ruby-sdk/oauth-client-credentials-default/.rubocop.yml b/seed/ruby-sdk/oauth-client-credentials-default/.rubocop.yml new file mode 100644 index 00000000000..c1d2344d6e6 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/.rubocop.yml @@ -0,0 +1,36 @@ +AllCops: + TargetRubyVersion: 2.7 + +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + Enabled: true + EnforcedStyle: double_quotes + +Layout/FirstHashElementLineBreak: + Enabled: true + +Layout/MultilineHashKeyLineBreaks: + Enabled: true + +# Generated files may be more complex than standard, disable +# these rules for now as a known limitation. +Metrics/ParameterLists: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false diff --git a/seed/ruby-sdk/oauth-client-credentials-default/Gemfile b/seed/ruby-sdk/oauth-client-credentials-default/Gemfile new file mode 100644 index 00000000000..49bd9cd0173 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +gem "minitest", "~> 5.0" +gem "rake", "~> 13.0" +gem "rubocop", "~> 1.21" diff --git a/seed/ruby-sdk/oauth-client-credentials-default/README.md b/seed/ruby-sdk/oauth-client-credentials-default/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ruby-sdk/oauth-client-credentials-default/Rakefile b/seed/ruby-sdk/oauth-client-credentials-default/Rakefile new file mode 100644 index 00000000000..2bdbce0cf2c --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/Rakefile @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "rake/testtask" +require "rubocop/rake_task" + +task default: %i[test rubocop] + +Rake::TestTask.new do |t| + t.pattern = "./test/**/test_*.rb" +end + +RuboCop::RakeTask.new diff --git a/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec b/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec new file mode 100644 index 00000000000..b8c813b3454 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require_relative "lib/gemconfig" + +Gem::Specification.new do |spec| + spec.name = "fern_oauth_client_credentials_default" + spec.version = "0.0.1" + spec.authors = SeedOauthClientCredentialsDefaultClient::Gemconfig::AUTHORS + spec.email = SeedOauthClientCredentialsDefaultClient::Gemconfig::EMAIL + spec.summary = SeedOauthClientCredentialsDefaultClient::Gemconfig::SUMMARY + spec.description = SeedOauthClientCredentialsDefaultClient::Gemconfig::DESCRIPTION + spec.homepage = SeedOauthClientCredentialsDefaultClient::Gemconfig::HOMEPAGE + spec.required_ruby_version = ">= 2.7.0" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = SeedOauthClientCredentialsDefaultClient::Gemconfig::SOURCE_CODE_URI + spec.metadata["changelog_uri"] = SeedOauthClientCredentialsDefaultClient::Gemconfig::CHANGELOG_URI + spec.files = Dir.glob("lib/**/*") + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb new file mode 100644 index 00000000000..7fb344e044f --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative "fern_oauth_client_credentials_default/auth/types/token_response" diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/types/token_response.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/types/token_response.rb new file mode 100644 index 00000000000..0545f83ec93 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/types/token_response.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "ostruct" +require "json" + +module SeedOauthClientCredentialsDefaultClient + class Auth + # An OAuth token response. + class TokenResponse + # @return [String] + attr_reader :access_token + # @return [Integer] + attr_reader :expires_in + # @return [OpenStruct] Additional properties unmapped to the current class definition + attr_reader :additional_properties + # @return [Object] + attr_reader :_field_set + protected :_field_set + + OMIT = Object.new + + # @param access_token [String] + # @param expires_in [Integer] + # @param additional_properties [OpenStruct] Additional properties unmapped to the current class definition + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def initialize(access_token:, expires_in:, additional_properties: nil) + @access_token = access_token + @expires_in = expires_in + @additional_properties = additional_properties + @_field_set = { "access_token": access_token, "expires_in": expires_in } + end + + # Deserialize a JSON object to an instance of TokenResponse + # + # @param json_object [String] + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def self.from_json(json_object:) + struct = JSON.parse(json_object, object_class: OpenStruct) + access_token = struct["access_token"] + expires_in = struct["expires_in"] + new( + access_token: access_token, + expires_in: expires_in, + additional_properties: struct + ) + end + + # Serialize an instance of TokenResponse to a JSON object + # + # @return [String] + def to_json(*_args) + @_field_set&.to_json + end + + # Leveraged for Union-type generation, validate_raw attempts to parse the given + # hash and check each fields type against the current object's property + # definitions. + # + # @param obj [Object] + # @return [Void] + def self.validate_raw(obj:) + obj.access_token.is_a?(String) != false || raise("Passed value for field obj.access_token is not the expected type, validation failed.") + obj.expires_in.is_a?(Integer) != false || raise("Passed value for field obj.expires_in is not the expected type, validation failed.") + end + end + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/gemconfig.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/gemconfig.rb new file mode 100644 index 00000000000..898f11b2c7d --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/gemconfig.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module SeedOauthClientCredentialsDefaultClient + module Gemconfig + VERSION = "" + AUTHORS = [""].freeze + EMAIL = "" + SUMMARY = "" + DESCRIPTION = "" + HOMEPAGE = "https://github.com/oauth-client-credentials-default/fern" + SOURCE_CODE_URI = "https://github.com/oauth-client-credentials-default/fern" + CHANGELOG_URI = "https://github.com/oauth-client-credentials-default/fern/blob/master/CHANGELOG.md" + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/snippet-templates.json b/seed/ruby-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ruby-sdk/oauth-client-credentials-default/snippet.json b/seed/ruby-sdk/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ruby-sdk/oauth-client-credentials-default/test/test_fern_oauth_client_credentials_default.rb b/seed/ruby-sdk/oauth-client-credentials-default/test/test_fern_oauth_client_credentials_default.rb new file mode 100644 index 00000000000..ff998941514 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/test/test_fern_oauth_client_credentials_default.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require_relative "test_helper" +require "fern_oauth_client_credentials_default" + +# Basic SeedOauthClientCredentialsDefaultClient tests +class TestSeedOauthClientCredentialsDefaultClient < Minitest::Test + def test_function + # SeedOauthClientCredentialsDefaultClient::Client.new + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/test/test_helper.rb b/seed/ruby-sdk/oauth-client-credentials-default/test/test_helper.rb new file mode 100644 index 00000000000..6b7dd541aa5 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/test/test_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) + +require "minitest/autorun" +require "fern_oauth_client_credentials_default" diff --git a/seed/ts-express/oauth-client-credentials-default/.inputs/config.json b/seed/ts-express/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..a4518867f06 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,23 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "downloadFiles" + }, + "path": "/fern/output", + "publishingMetadata": null + }, + "publish": null, + "customConfig": { + "outputSourceFiles": true + }, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/ts-express/oauth-client-credentials-default/.inputs/ir.json b/seed/ts-express/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..ed3c996cde7 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1223 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": { + "endpointId": "endpoint_auth.getToken", + "serviceId": "service_auth", + "subpackageId": "subpackage_auth" + }, + "requestProperties": { + "clientId": { + "propertyPath": [], + "property": { + "type": "body", + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "clientSecret": { + "propertyPath": [], + "property": { + "type": "body", + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "scopes": null + }, + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ], + "extra-properties": false + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "status-code": null + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file diff --git a/seed/ts-express/oauth-client-credentials-default/.mock/definition/api.yml b/seed/ts-express/oauth-client-credentials-default/.mock/definition/api.yml new file mode 100644 index 00000000000..e94a5d4e99d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.mock/definition/api.yml @@ -0,0 +1,11 @@ +name: oauth-client-credentials-default +imports: + auth: auth.yml + +auth: OAuthScheme +auth-schemes: + OAuthScheme: + scheme: oauth + type: client-credentials + get-token: + endpoint: auth.getToken \ No newline at end of file diff --git a/seed/ts-express/oauth-client-credentials-default/.mock/definition/auth.yml b/seed/ts-express/oauth-client-credentials-default/.mock/definition/auth.yml new file mode 100644 index 00000000000..ca7f4017566 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.mock/definition/auth.yml @@ -0,0 +1,23 @@ +types: + TokenResponse: + docs: | + An OAuth token response. + properties: + access_token: string + expires_in: integer + +service: + auth: false + base-path: / + endpoints: + getToken: + path: /token + method: POST + request: + name: GetTokenRequest + body: + properties: + client_id: string + client_secret: string + grant_type: literal<"client_credentials"> + response: TokenResponse \ No newline at end of file diff --git a/seed/ts-express/oauth-client-credentials-default/.mock/fern.config.json b/seed/ts-express/oauth-client-credentials-default/.mock/fern.config.json new file mode 100644 index 00000000000..4c8e54ac313 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.mock/fern.config.json @@ -0,0 +1 @@ +{"organization": "fern-test", "version": "*"} \ No newline at end of file diff --git a/seed/ts-express/oauth-client-credentials-default/.mock/generators.yml b/seed/ts-express/oauth-client-credentials-default/.mock/generators.yml new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/.mock/generators.yml @@ -0,0 +1 @@ +{} diff --git a/seed/ts-express/oauth-client-credentials-default/api/index.ts b/seed/ts-express/oauth-client-credentials-default/api/index.ts new file mode 100644 index 00000000000..3e5335fe421 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/index.ts @@ -0,0 +1 @@ +export * from "./resources"; diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/index.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/index.ts new file mode 100644 index 00000000000..fcc81debec4 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./types"; +export * from "./service"; diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/AuthService.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/AuthService.ts new file mode 100644 index 00000000000..c86ec5c8ea2 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/AuthService.ts @@ -0,0 +1,85 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as SeedOauthClientCredentialsDefault from "../../../index"; +import express from "express"; +import * as serializers from "../../../../serialization/index"; +import * as errors from "../../../../errors/index"; + +export interface AuthServiceMethods { + getToken( + req: express.Request< + never, + SeedOauthClientCredentialsDefault.TokenResponse, + SeedOauthClientCredentialsDefault.GetTokenRequest, + never + >, + res: { + send: (responseBody: SeedOauthClientCredentialsDefault.TokenResponse) => Promise; + cookie: (cookie: string, value: string, options?: express.CookieOptions) => void; + locals: any; + } + ): void | Promise; +} + +export class AuthService { + private router; + + constructor(private readonly methods: AuthServiceMethods, middleware: express.RequestHandler[] = []) { + this.router = express.Router({ mergeParams: true }).use( + express.json({ + strict: false, + }), + ...middleware + ); + } + + public addMiddleware(handler: express.RequestHandler): this { + this.router.use(handler); + return this; + } + + public toRouter(): express.Router { + this.router.post("/token", async (req, res, next) => { + const request = await serializers.GetTokenRequest.parse(req.body); + if (request.ok) { + req.body = request.value; + try { + await this.methods.getToken(req as any, { + send: async (responseBody) => { + res.json( + await serializers.TokenResponse.jsonOrThrow(responseBody, { + unrecognizedObjectKeys: "strip", + }) + ); + }, + cookie: res.cookie.bind(res), + locals: res.locals, + }); + next(); + } catch (error) { + if (error instanceof errors.SeedOauthClientCredentialsDefaultError) { + console.warn( + `Endpoint 'getToken' unexpectedly threw ${error.constructor.name}.` + + ` If this was intentional, please add ${error.constructor.name} to` + + " the endpoint's errors list in your Fern Definition." + ); + await error.send(res); + } else { + res.status(500).json("Internal Server Error"); + } + next(error); + } + } else { + res.status(422).json({ + errors: request.errors.map( + (error) => ["request", ...error.path].join(" -> ") + ": " + error.message + ), + }); + next(request.errors); + } + }); + return this.router; + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/index.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/index.ts new file mode 100644 index 00000000000..415726b7fea --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/index.ts @@ -0,0 +1 @@ +export * from "./requests"; diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/GetTokenRequest.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/GetTokenRequest.ts new file mode 100644 index 00000000000..e108013546a --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/GetTokenRequest.ts @@ -0,0 +1,9 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +export interface GetTokenRequest { + clientId: string; + clientSecret: string; + grantType: "client_credentials"; +} diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/index.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/index.ts new file mode 100644 index 00000000000..c890bee6072 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/service/requests/index.ts @@ -0,0 +1 @@ +export { GetTokenRequest } from "./GetTokenRequest"; diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/TokenResponse.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/TokenResponse.ts new file mode 100644 index 00000000000..f25212b5706 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/TokenResponse.ts @@ -0,0 +1,11 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +/** + * An OAuth token response. + */ +export interface TokenResponse { + accessToken: string; + expiresIn: number; +} diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/index.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/index.ts new file mode 100644 index 00000000000..6848a730c91 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/auth/types/index.ts @@ -0,0 +1 @@ +export * from "./TokenResponse"; diff --git a/seed/ts-express/oauth-client-credentials-default/api/resources/index.ts b/seed/ts-express/oauth-client-credentials-default/api/resources/index.ts new file mode 100644 index 00000000000..f6dde5f4e87 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/api/resources/index.ts @@ -0,0 +1,3 @@ +export * as auth from "./auth"; +export * from "./auth/types"; +export * from "./auth/service/requests"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/index.ts b/seed/ts-express/oauth-client-credentials-default/core/index.ts new file mode 100644 index 00000000000..3ae53c06d38 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/index.ts @@ -0,0 +1 @@ +export * as serialization from "./schemas"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/Schema.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/Schema.ts new file mode 100644 index 00000000000..870f373ba87 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/Schema.ts @@ -0,0 +1,94 @@ +import { SchemaUtils } from "./builders"; +import { MaybePromise } from "./utils/MaybePromise"; + +export type Schema = BaseSchema & SchemaUtils; + +export type inferRaw = S extends Schema ? Raw : never; +export type inferParsed = S extends Schema ? Parsed : never; + +export interface BaseSchema { + parse: (raw: unknown, opts?: SchemaOptions) => MaybePromise>; + json: (parsed: unknown, opts?: SchemaOptions) => MaybePromise>; + getType: () => SchemaType | Promise; +} + +export const SchemaType = { + DATE: "date", + ENUM: "enum", + LIST: "list", + STRING_LITERAL: "stringLiteral", + BOOLEAN_LITERAL: "booleanLiteral", + OBJECT: "object", + ANY: "any", + BOOLEAN: "boolean", + NUMBER: "number", + STRING: "string", + UNKNOWN: "unknown", + RECORD: "record", + SET: "set", + UNION: "union", + UNDISCRIMINATED_UNION: "undiscriminatedUnion", + OPTIONAL: "optional", +} as const; +export type SchemaType = typeof SchemaType[keyof typeof SchemaType]; + +export type MaybeValid = Valid | Invalid; + +export interface Valid { + ok: true; + value: T; +} + +export interface Invalid { + ok: false; + errors: ValidationError[]; +} + +export interface ValidationError { + path: string[]; + message: string; +} + +export interface SchemaOptions { + /** + * how to handle unrecognized keys in objects + * + * @default "fail" + */ + unrecognizedObjectKeys?: "fail" | "passthrough" | "strip"; + + /** + * whether to fail when an unrecognized discriminant value is + * encountered in a union + * + * @default false + */ + allowUnrecognizedUnionMembers?: boolean; + + /** + * whether to fail when an unrecognized enum value is encountered + * + * @default false + */ + allowUnrecognizedEnumValues?: boolean; + + /** + * whether to allow data that doesn't conform to the schema. + * invalid data is passed through without transformation. + * + * when this is enabled, .parse() and .json() will always + * return `ok: true`. `.parseOrThrow()` and `.jsonOrThrow()` + * will never fail. + * + * @default false + */ + skipValidation?: boolean; + + /** + * each validation failure contains a "path" property, which is + * the breadcrumbs to the offending node in the JSON. you can supply + * a prefix that is prepended to all the errors' paths. this can be + * helpful for zurg's internal debug logging. + */ + breadcrumbsPrefix?: string[]; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/date.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/date.ts new file mode 100644 index 00000000000..b70f24b045a --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/date.ts @@ -0,0 +1,65 @@ +import { BaseSchema, Schema, SchemaType } from "../../Schema"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { getSchemaUtils } from "../schema-utils"; + +// https://stackoverflow.com/questions/12756159/regex-and-iso8601-formatted-datetime +const ISO_8601_REGEX = + /^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/; + +export function date(): Schema { + const baseSchema: BaseSchema = { + parse: (raw, { breadcrumbsPrefix = [] } = {}) => { + if (typeof raw !== "string") { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(raw, "string"), + }, + ], + }; + } + if (!ISO_8601_REGEX.test(raw)) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(raw, "ISO 8601 date string"), + }, + ], + }; + } + return { + ok: true, + value: new Date(raw), + }; + }, + json: (date, { breadcrumbsPrefix = [] } = {}) => { + if (date instanceof Date) { + return { + ok: true, + value: date.toISOString(), + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(date, "Date object"), + }, + ], + }; + } + }, + getType: () => SchemaType.DATE, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/index.ts new file mode 100644 index 00000000000..187b29040f6 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/date/index.ts @@ -0,0 +1 @@ +export { date } from "./date"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/enum.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/enum.ts new file mode 100644 index 00000000000..c1e24d69dec --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/enum.ts @@ -0,0 +1,43 @@ +import { Schema, SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export function enum_(values: E): Schema { + const validValues = new Set(values); + + const schemaCreator = createIdentitySchemaCreator( + SchemaType.ENUM, + (value, { allowUnrecognizedEnumValues, breadcrumbsPrefix = [] } = {}) => { + if (typeof value !== "string") { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "string"), + }, + ], + }; + } + + if (!validValues.has(value) && !allowUnrecognizedEnumValues) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "enum"), + }, + ], + }; + } + + return { + ok: true, + value: value as U, + }; + } + ); + + return schemaCreator(); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/index.ts new file mode 100644 index 00000000000..fe6faed93e3 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/enum/index.ts @@ -0,0 +1 @@ +export { enum_ } from "./enum"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/index.ts new file mode 100644 index 00000000000..050cd2c4efb --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/index.ts @@ -0,0 +1,13 @@ +export * from "./date"; +export * from "./enum"; +export * from "./lazy"; +export * from "./list"; +export * from "./literals"; +export * from "./object"; +export * from "./object-like"; +export * from "./primitives"; +export * from "./record"; +export * from "./schema-utils"; +export * from "./set"; +export * from "./undiscriminated-union"; +export * from "./union"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/index.ts new file mode 100644 index 00000000000..77420fb031c --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/index.ts @@ -0,0 +1,3 @@ +export { lazy } from "./lazy"; +export type { SchemaGetter } from "./lazy"; +export { lazyObject } from "./lazyObject"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazy.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazy.ts new file mode 100644 index 00000000000..a665472d22c --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazy.ts @@ -0,0 +1,34 @@ +import { BaseSchema, Schema } from "../../Schema"; +import { getSchemaUtils } from "../schema-utils"; + +export type SchemaGetter> = () => SchemaType | Promise; + +export function lazy(getter: SchemaGetter>): Schema { + const baseSchema = constructLazyBaseSchema(getter); + return { + ...baseSchema, + ...getSchemaUtils(baseSchema), + }; +} + +export function constructLazyBaseSchema( + getter: SchemaGetter> +): BaseSchema { + return { + parse: async (raw, opts) => (await getMemoizedSchema(getter)).parse(raw, opts), + json: async (parsed, opts) => (await getMemoizedSchema(getter)).json(parsed, opts), + getType: async () => (await getMemoizedSchema(getter)).getType(), + }; +} + +type MemoizedGetter> = SchemaGetter & { __zurg_memoized?: SchemaType }; + +export async function getMemoizedSchema>( + getter: SchemaGetter +): Promise { + const castedGetter = getter as MemoizedGetter; + if (castedGetter.__zurg_memoized == null) { + castedGetter.__zurg_memoized = await getter(); + } + return castedGetter.__zurg_memoized; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazyObject.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazyObject.ts new file mode 100644 index 00000000000..e48c0166677 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/lazy/lazyObject.ts @@ -0,0 +1,20 @@ +import { getObjectUtils } from "../object"; +import { getObjectLikeUtils } from "../object-like"; +import { BaseObjectSchema, ObjectSchema } from "../object/types"; +import { getSchemaUtils } from "../schema-utils"; +import { constructLazyBaseSchema, getMemoizedSchema, SchemaGetter } from "./lazy"; + +export function lazyObject(getter: SchemaGetter>): ObjectSchema { + const baseSchema: BaseObjectSchema = { + ...constructLazyBaseSchema(getter), + _getRawProperties: async () => (await getMemoizedSchema(getter))._getRawProperties(), + _getParsedProperties: async () => (await getMemoizedSchema(getter))._getParsedProperties(), + }; + + return { + ...baseSchema, + ...getSchemaUtils(baseSchema), + ...getObjectLikeUtils(baseSchema), + ...getObjectUtils(baseSchema), + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/index.ts new file mode 100644 index 00000000000..25f4bcc1737 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/index.ts @@ -0,0 +1 @@ +export { list } from "./list"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/list.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/list.ts new file mode 100644 index 00000000000..b333321b507 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/list/list.ts @@ -0,0 +1,74 @@ +import { BaseSchema, MaybeValid, Schema, SchemaType, ValidationError } from "../../Schema"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { MaybePromise } from "../../utils/MaybePromise"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { getSchemaUtils } from "../schema-utils"; + +export function list(schema: Schema): Schema { + const baseSchema: BaseSchema = { + parse: async (raw, opts) => + validateAndTransformArray(raw, (item, index) => + schema.parse(item, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `[${index}]`], + }) + ), + json: (parsed, opts) => + validateAndTransformArray(parsed, (item, index) => + schema.json(item, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `[${index}]`], + }) + ), + getType: () => SchemaType.LIST, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; +} + +async function validateAndTransformArray( + value: unknown, + transformItem: (item: Raw, index: number) => MaybePromise> +): Promise> { + if (!Array.isArray(value)) { + return { + ok: false, + errors: [ + { + message: getErrorMessageForIncorrectType(value, "list"), + path: [], + }, + ], + }; + } + + const maybeValidItems = await Promise.all(value.map((item, index) => transformItem(item, index))); + + return maybeValidItems.reduce>( + (acc, item) => { + if (acc.ok && item.ok) { + return { + ok: true, + value: [...acc.value, item.value], + }; + } + + const errors: ValidationError[] = []; + if (!acc.ok) { + errors.push(...acc.errors); + } + if (!item.ok) { + errors.push(...item.errors); + } + + return { + ok: false, + errors, + }; + }, + { ok: true, value: [] } + ); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/booleanLiteral.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/booleanLiteral.ts new file mode 100644 index 00000000000..a83d22cd48a --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/booleanLiteral.ts @@ -0,0 +1,29 @@ +import { Schema, SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export function booleanLiteral(literal: V): Schema { + const schemaCreator = createIdentitySchemaCreator( + SchemaType.BOOLEAN_LITERAL, + (value, { breadcrumbsPrefix = [] } = {}) => { + if (value === literal) { + return { + ok: true, + value: literal, + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, `${literal.toString()}`), + }, + ], + }; + } + } + ); + + return schemaCreator(); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/index.ts new file mode 100644 index 00000000000..d2bf08fc6ca --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/index.ts @@ -0,0 +1,2 @@ +export { stringLiteral } from "./stringLiteral"; +export { booleanLiteral } from "./booleanLiteral"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/stringLiteral.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/stringLiteral.ts new file mode 100644 index 00000000000..3939b76b48d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/literals/stringLiteral.ts @@ -0,0 +1,29 @@ +import { Schema, SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export function stringLiteral(literal: V): Schema { + const schemaCreator = createIdentitySchemaCreator( + SchemaType.STRING_LITERAL, + (value, { breadcrumbsPrefix = [] } = {}) => { + if (value === literal) { + return { + ok: true, + value: literal, + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, `"${literal}"`), + }, + ], + }; + } + } + ); + + return schemaCreator(); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/getObjectLikeUtils.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/getObjectLikeUtils.ts new file mode 100644 index 00000000000..270ea170c85 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/getObjectLikeUtils.ts @@ -0,0 +1,79 @@ +import { BaseSchema } from "../../Schema"; +import { filterObject } from "../../utils/filterObject"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { isPlainObject } from "../../utils/isPlainObject"; +import { getSchemaUtils } from "../schema-utils"; +import { ObjectLikeSchema, ObjectLikeUtils } from "./types"; + +export function getObjectLikeUtils(schema: BaseSchema): ObjectLikeUtils { + return { + withParsedProperties: (properties) => withParsedProperties(schema, properties), + }; +} + +/** + * object-like utils are defined in one file to resolve issues with circular imports + */ + +export function withParsedProperties( + objectLike: BaseSchema, + properties: { [K in keyof Properties]: Properties[K] | ((parsed: ParsedObjectShape) => Properties[K]) } +): ObjectLikeSchema { + const objectSchema: BaseSchema = { + parse: async (raw, opts) => { + const parsedObject = await objectLike.parse(raw, opts); + if (!parsedObject.ok) { + return parsedObject; + } + + const additionalProperties = Object.entries(properties).reduce>( + (processed, [key, value]) => { + return { + ...processed, + [key]: typeof value === "function" ? value(parsedObject.value) : value, + }; + }, + {} + ); + + return { + ok: true, + value: { + ...parsedObject.value, + ...(additionalProperties as Properties), + }, + }; + }, + + json: (parsed, opts) => { + if (!isPlainObject(parsed)) { + return { + ok: false, + errors: [ + { + path: opts?.breadcrumbsPrefix ?? [], + message: getErrorMessageForIncorrectType(parsed, "object"), + }, + ], + }; + } + + // strip out added properties + const addedPropertyKeys = new Set(Object.keys(properties)); + const parsedWithoutAddedProperties = filterObject( + parsed, + Object.keys(parsed).filter((key) => !addedPropertyKeys.has(key)) + ); + + return objectLike.json(parsedWithoutAddedProperties as ParsedObjectShape, opts); + }, + + getType: () => objectLike.getType(), + }; + + return { + ...objectSchema, + ...getSchemaUtils(objectSchema), + ...getObjectLikeUtils(objectSchema), + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/index.ts new file mode 100644 index 00000000000..c342e72cf9d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/index.ts @@ -0,0 +1,2 @@ +export { getObjectLikeUtils, withParsedProperties } from "./getObjectLikeUtils"; +export type { ObjectLikeSchema, ObjectLikeUtils } from "./types"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/types.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/types.ts new file mode 100644 index 00000000000..75b3698729c --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object-like/types.ts @@ -0,0 +1,11 @@ +import { BaseSchema, Schema } from "../../Schema"; + +export type ObjectLikeSchema = Schema & + BaseSchema & + ObjectLikeUtils; + +export interface ObjectLikeUtils { + withParsedProperties: >(properties: { + [K in keyof T]: T[K] | ((parsed: Parsed) => T[K]); + }) => ObjectLikeSchema; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/index.ts new file mode 100644 index 00000000000..e3f4388db28 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/index.ts @@ -0,0 +1,22 @@ +export { getObjectUtils, object } from "./object"; +export { objectWithoutOptionalProperties } from "./objectWithoutOptionalProperties"; +export type { + inferObjectWithoutOptionalPropertiesSchemaFromPropertySchemas, + inferParsedObjectWithoutOptionalPropertiesFromPropertySchemas, +} from "./objectWithoutOptionalProperties"; +export { isProperty, property } from "./property"; +export type { Property } from "./property"; +export type { + BaseObjectSchema, + inferObjectSchemaFromPropertySchemas, + inferParsedObject, + inferParsedObjectFromPropertySchemas, + inferParsedPropertySchema, + inferRawKey, + inferRawObject, + inferRawObjectFromPropertySchemas, + inferRawPropertySchema, + ObjectSchema, + ObjectUtils, + PropertySchemas, +} from "./types"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/object.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/object.ts new file mode 100644 index 00000000000..6427678b228 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/object.ts @@ -0,0 +1,333 @@ +import { MaybeValid, Schema, SchemaType, ValidationError } from "../../Schema"; +import { entries } from "../../utils/entries"; +import { filterObject } from "../../utils/filterObject"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { isPlainObject } from "../../utils/isPlainObject"; +import { keys } from "../../utils/keys"; +import { MaybePromise } from "../../utils/MaybePromise"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { partition } from "../../utils/partition"; +import { getObjectLikeUtils } from "../object-like"; +import { getSchemaUtils } from "../schema-utils"; +import { isProperty } from "./property"; +import { + BaseObjectSchema, + inferObjectSchemaFromPropertySchemas, + inferParsedObjectFromPropertySchemas, + inferRawObjectFromPropertySchemas, + ObjectSchema, + ObjectUtils, + PropertySchemas, +} from "./types"; + +interface ObjectPropertyWithRawKey { + rawKey: string; + parsedKey: string; + valueSchema: Schema; +} + +export function object>( + schemas: T +): inferObjectSchemaFromPropertySchemas { + const baseSchema: BaseObjectSchema< + inferRawObjectFromPropertySchemas, + inferParsedObjectFromPropertySchemas + > = { + _getRawProperties: () => + Promise.resolve( + Object.entries(schemas).map(([parsedKey, propertySchema]) => + isProperty(propertySchema) ? propertySchema.rawKey : parsedKey + ) as unknown as (keyof inferRawObjectFromPropertySchemas)[] + ), + _getParsedProperties: () => + Promise.resolve(keys(schemas) as unknown as (keyof inferParsedObjectFromPropertySchemas)[]), + + parse: async (raw, opts) => { + const rawKeyToProperty: Record = {}; + const requiredKeys: string[] = []; + + for (const [parsedKey, schemaOrObjectProperty] of entries(schemas)) { + const rawKey = isProperty(schemaOrObjectProperty) ? schemaOrObjectProperty.rawKey : parsedKey; + const valueSchema: Schema = isProperty(schemaOrObjectProperty) + ? schemaOrObjectProperty.valueSchema + : schemaOrObjectProperty; + + const property: ObjectPropertyWithRawKey = { + rawKey, + parsedKey: parsedKey as string, + valueSchema, + }; + + rawKeyToProperty[rawKey] = property; + + if (isSchemaRequired(valueSchema)) { + requiredKeys.push(rawKey); + } + } + + return validateAndTransformObject({ + value: raw, + requiredKeys, + getProperty: (rawKey) => { + const property = rawKeyToProperty[rawKey]; + if (property == null) { + return undefined; + } + return { + transformedKey: property.parsedKey, + transform: (propertyValue) => + property.valueSchema.parse(propertyValue, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), rawKey], + }), + }; + }, + unrecognizedObjectKeys: opts?.unrecognizedObjectKeys, + skipValidation: opts?.skipValidation, + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + + json: async (parsed, opts) => { + const requiredKeys: string[] = []; + + for (const [parsedKey, schemaOrObjectProperty] of entries(schemas)) { + const valueSchema: Schema = isProperty(schemaOrObjectProperty) + ? schemaOrObjectProperty.valueSchema + : schemaOrObjectProperty; + + if (isSchemaRequired(valueSchema)) { + requiredKeys.push(parsedKey as string); + } + } + + return validateAndTransformObject({ + value: parsed, + requiredKeys, + getProperty: ( + parsedKey + ): + | { transformedKey: string; transform: (propertyValue: unknown) => MaybePromise> } + | undefined => { + const property = schemas[parsedKey as keyof T]; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (property == null) { + return undefined; + } + + if (isProperty(property)) { + return { + transformedKey: property.rawKey, + transform: (propertyValue) => + property.valueSchema.json(propertyValue, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), parsedKey], + }), + }; + } else { + return { + transformedKey: parsedKey, + transform: (propertyValue) => + property.json(propertyValue, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), parsedKey], + }), + }; + } + }, + unrecognizedObjectKeys: opts?.unrecognizedObjectKeys, + skipValidation: opts?.skipValidation, + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + + getType: () => SchemaType.OBJECT, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + ...getObjectLikeUtils(baseSchema), + ...getObjectUtils(baseSchema), + }; +} + +async function validateAndTransformObject({ + value, + requiredKeys, + getProperty, + unrecognizedObjectKeys = "fail", + skipValidation = false, + breadcrumbsPrefix = [], +}: { + value: unknown; + requiredKeys: string[]; + getProperty: ( + preTransformedKey: string + ) => { transformedKey: string; transform: (propertyValue: unknown) => MaybePromise> } | undefined; + unrecognizedObjectKeys: "fail" | "passthrough" | "strip" | undefined; + skipValidation: boolean | undefined; + breadcrumbsPrefix: string[] | undefined; +}): Promise> { + if (!isPlainObject(value)) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "object"), + }, + ], + }; + } + + const missingRequiredKeys = new Set(requiredKeys); + const errors: ValidationError[] = []; + const transformed: Record = {}; + + for (const [preTransformedKey, preTransformedItemValue] of Object.entries(value)) { + const property = getProperty(preTransformedKey); + + if (property != null) { + missingRequiredKeys.delete(preTransformedKey); + + const value = await property.transform(preTransformedItemValue); + if (value.ok) { + transformed[property.transformedKey] = value.value; + } else { + transformed[preTransformedKey] = preTransformedItemValue; + errors.push(...value.errors); + } + } else { + switch (unrecognizedObjectKeys) { + case "fail": + errors.push({ + path: [...breadcrumbsPrefix, preTransformedKey], + message: `Unexpected key "${preTransformedKey}"`, + }); + break; + case "strip": + break; + case "passthrough": + transformed[preTransformedKey] = preTransformedItemValue; + break; + } + } + } + + errors.push( + ...requiredKeys + .filter((key) => missingRequiredKeys.has(key)) + .map((key) => ({ + path: breadcrumbsPrefix, + message: `Missing required key "${key}"`, + })) + ); + + if (errors.length === 0 || skipValidation) { + return { + ok: true, + value: transformed as Transformed, + }; + } else { + return { + ok: false, + errors, + }; + } +} + +export function getObjectUtils(schema: BaseObjectSchema): ObjectUtils { + return { + extend: (extension: ObjectSchema) => { + const baseSchema: BaseObjectSchema = { + _getParsedProperties: async () => [ + ...(await schema._getParsedProperties()), + ...(await extension._getParsedProperties()), + ], + _getRawProperties: async () => [ + ...(await schema._getRawProperties()), + ...(await extension._getRawProperties()), + ], + parse: async (raw, opts) => { + return validateAndTransformExtendedObject({ + extensionKeys: await extension._getRawProperties(), + value: raw, + transformBase: (rawBase) => schema.parse(rawBase, opts), + transformExtension: (rawExtension) => extension.parse(rawExtension, opts), + }); + }, + json: async (parsed, opts) => { + return validateAndTransformExtendedObject({ + extensionKeys: await extension._getParsedProperties(), + value: parsed, + transformBase: (parsedBase) => schema.json(parsedBase, opts), + transformExtension: (parsedExtension) => extension.json(parsedExtension, opts), + }); + }, + getType: () => SchemaType.OBJECT, + }; + + return { + ...baseSchema, + ...getSchemaUtils(baseSchema), + ...getObjectLikeUtils(baseSchema), + ...getObjectUtils(baseSchema), + }; + }, + }; +} + +async function validateAndTransformExtendedObject({ + extensionKeys, + value, + transformBase, + transformExtension, +}: { + extensionKeys: (keyof PreTransformedExtension)[]; + value: unknown; + transformBase: (value: unknown) => MaybePromise>; + transformExtension: (value: unknown) => MaybePromise>; +}): Promise> { + const extensionPropertiesSet = new Set(extensionKeys); + const [extensionProperties, baseProperties] = partition(keys(value), (key) => + extensionPropertiesSet.has(key as keyof PreTransformedExtension) + ); + + const transformedBase = await transformBase(filterObject(value, baseProperties)); + const transformedExtension = await transformExtension(filterObject(value, extensionProperties)); + + if (transformedBase.ok && transformedExtension.ok) { + return { + ok: true, + value: { + ...transformedBase.value, + ...transformedExtension.value, + }, + }; + } else { + return { + ok: false, + errors: [ + ...(transformedBase.ok ? [] : transformedBase.errors), + ...(transformedExtension.ok ? [] : transformedExtension.errors), + ], + }; + } +} + +function isSchemaRequired(schema: Schema): boolean { + return !isSchemaOptional(schema); +} + +function isSchemaOptional(schema: Schema): boolean { + switch (schema.getType()) { + case SchemaType.ANY: + case SchemaType.UNKNOWN: + case SchemaType.OPTIONAL: + return true; + default: + return false; + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/objectWithoutOptionalProperties.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/objectWithoutOptionalProperties.ts new file mode 100644 index 00000000000..a0951f48efc --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/objectWithoutOptionalProperties.ts @@ -0,0 +1,18 @@ +import { object } from "./object"; +import { inferParsedPropertySchema, inferRawObjectFromPropertySchemas, ObjectSchema, PropertySchemas } from "./types"; + +export function objectWithoutOptionalProperties>( + schemas: T +): inferObjectWithoutOptionalPropertiesSchemaFromPropertySchemas { + return object(schemas) as unknown as inferObjectWithoutOptionalPropertiesSchemaFromPropertySchemas; +} + +export type inferObjectWithoutOptionalPropertiesSchemaFromPropertySchemas> = + ObjectSchema< + inferRawObjectFromPropertySchemas, + inferParsedObjectWithoutOptionalPropertiesFromPropertySchemas + >; + +export type inferParsedObjectWithoutOptionalPropertiesFromPropertySchemas> = { + [K in keyof T]: inferParsedPropertySchema; +}; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/property.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/property.ts new file mode 100644 index 00000000000..d245c4b193a --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/property.ts @@ -0,0 +1,23 @@ +import { Schema } from "../../Schema"; + +export function property( + rawKey: RawKey, + valueSchema: Schema +): Property { + return { + rawKey, + valueSchema, + isProperty: true, + }; +} + +export interface Property { + rawKey: RawKey; + valueSchema: Schema; + isProperty: true; +} + +export function isProperty>(maybeProperty: unknown): maybeProperty is O { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + return (maybeProperty as O).isProperty; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/types.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/types.ts new file mode 100644 index 00000000000..17cff4f86dd --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/object/types.ts @@ -0,0 +1,72 @@ +import { BaseSchema, inferParsed, inferRaw, Schema } from "../../Schema"; +import { addQuestionMarksToNullableProperties } from "../../utils/addQuestionMarksToNullableProperties"; +import { ObjectLikeUtils } from "../object-like"; +import { SchemaUtils } from "../schema-utils"; +import { Property } from "./property"; + +export type ObjectSchema = BaseObjectSchema & + ObjectLikeUtils & + ObjectUtils & + SchemaUtils; + +export interface BaseObjectSchema extends BaseSchema { + _getRawProperties: () => Promise<(keyof Raw)[]>; + _getParsedProperties: () => Promise<(keyof Parsed)[]>; +} + +export interface ObjectUtils { + extend: ( + schemas: ObjectSchema + ) => ObjectSchema; +} + +export type inferRawObject> = O extends ObjectSchema ? Raw : never; + +export type inferParsedObject> = O extends ObjectSchema + ? Parsed + : never; + +export type inferObjectSchemaFromPropertySchemas> = ObjectSchema< + inferRawObjectFromPropertySchemas, + inferParsedObjectFromPropertySchemas +>; + +export type inferRawObjectFromPropertySchemas> = + addQuestionMarksToNullableProperties<{ + [ParsedKey in keyof T as inferRawKey]: inferRawPropertySchema; + }>; + +export type inferParsedObjectFromPropertySchemas> = + addQuestionMarksToNullableProperties<{ + [K in keyof T]: inferParsedPropertySchema; + }>; + +export type PropertySchemas = Record< + ParsedKeys, + Property | Schema +>; + +export type inferRawPropertySchema

| Schema> = P extends Property< + any, + infer Raw, + any +> + ? Raw + : P extends Schema + ? inferRaw

+ : never; + +export type inferParsedPropertySchema

| Schema> = P extends Property< + any, + any, + infer Parsed +> + ? Parsed + : P extends Schema + ? inferParsed

+ : never; + +export type inferRawKey< + ParsedKey extends string | number | symbol, + P extends Property | Schema +> = P extends Property ? Raw : ParsedKey; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/any.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/any.ts new file mode 100644 index 00000000000..fcaeb04255a --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/any.ts @@ -0,0 +1,4 @@ +import { SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; + +export const any = createIdentitySchemaCreator(SchemaType.ANY, (value) => ({ ok: true, value })); diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/boolean.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/boolean.ts new file mode 100644 index 00000000000..fad60562120 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/boolean.ts @@ -0,0 +1,25 @@ +import { SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export const boolean = createIdentitySchemaCreator( + SchemaType.BOOLEAN, + (value, { breadcrumbsPrefix = [] } = {}) => { + if (typeof value === "boolean") { + return { + ok: true, + value, + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "boolean"), + }, + ], + }; + } + } +); diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/index.ts new file mode 100644 index 00000000000..788f9416bfe --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/index.ts @@ -0,0 +1,5 @@ +export { any } from "./any"; +export { boolean } from "./boolean"; +export { number } from "./number"; +export { string } from "./string"; +export { unknown } from "./unknown"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/number.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/number.ts new file mode 100644 index 00000000000..c2689456936 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/number.ts @@ -0,0 +1,25 @@ +import { SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export const number = createIdentitySchemaCreator( + SchemaType.NUMBER, + (value, { breadcrumbsPrefix = [] } = {}) => { + if (typeof value === "number") { + return { + ok: true, + value, + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "number"), + }, + ], + }; + } + } +); diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/string.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/string.ts new file mode 100644 index 00000000000..949f1f2a630 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/string.ts @@ -0,0 +1,25 @@ +import { SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; + +export const string = createIdentitySchemaCreator( + SchemaType.STRING, + (value, { breadcrumbsPrefix = [] } = {}) => { + if (typeof value === "string") { + return { + ok: true, + value, + }; + } else { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "string"), + }, + ], + }; + } + } +); diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/unknown.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/unknown.ts new file mode 100644 index 00000000000..4d5249571f5 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/primitives/unknown.ts @@ -0,0 +1,4 @@ +import { SchemaType } from "../../Schema"; +import { createIdentitySchemaCreator } from "../../utils/createIdentitySchemaCreator"; + +export const unknown = createIdentitySchemaCreator(SchemaType.UNKNOWN, (value) => ({ ok: true, value })); diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/index.ts new file mode 100644 index 00000000000..82e25c5c2af --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/index.ts @@ -0,0 +1,2 @@ +export { record } from "./record"; +export type { BaseRecordSchema, RecordSchema } from "./types"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/record.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/record.ts new file mode 100644 index 00000000000..ac1cd22ade0 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/record.ts @@ -0,0 +1,131 @@ +import { MaybeValid, Schema, SchemaType, ValidationError } from "../../Schema"; +import { entries } from "../../utils/entries"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { isPlainObject } from "../../utils/isPlainObject"; +import { MaybePromise } from "../../utils/MaybePromise"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { getSchemaUtils } from "../schema-utils"; +import { BaseRecordSchema, RecordSchema } from "./types"; + +export function record( + keySchema: Schema, + valueSchema: Schema +): RecordSchema { + const baseSchema: BaseRecordSchema = { + parse: async (raw, opts) => { + return validateAndTransformRecord({ + value: raw, + isKeyNumeric: (await keySchema.getType()) === SchemaType.NUMBER, + transformKey: (key) => + keySchema.parse(key, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `${key} (key)`], + }), + transformValue: (value, key) => + valueSchema.parse(value, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `${key}`], + }), + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + json: async (parsed, opts) => { + return validateAndTransformRecord({ + value: parsed, + isKeyNumeric: (await keySchema.getType()) === SchemaType.NUMBER, + transformKey: (key) => + keySchema.json(key, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `${key} (key)`], + }), + transformValue: (value, key) => + valueSchema.json(value, { + ...opts, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), `${key}`], + }), + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + getType: () => SchemaType.RECORD, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; +} + +async function validateAndTransformRecord({ + value, + isKeyNumeric, + transformKey, + transformValue, + breadcrumbsPrefix = [], +}: { + value: unknown; + isKeyNumeric: boolean; + transformKey: (key: string | number) => MaybePromise>; + transformValue: (value: unknown, key: string | number) => MaybePromise>; + breadcrumbsPrefix: string[] | undefined; +}): Promise>> { + if (!isPlainObject(value)) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "object"), + }, + ], + }; + } + + return entries(value).reduce>>>( + async (accPromise, [stringKey, value]) => { + // skip nullish keys + if (value == null) { + return accPromise; + } + + const acc = await accPromise; + + let key: string | number = stringKey; + if (isKeyNumeric) { + const numberKey = stringKey.length > 0 ? Number(stringKey) : NaN; + if (!isNaN(numberKey)) { + key = numberKey; + } + } + const transformedKey = await transformKey(key); + + const transformedValue = await transformValue(value, key); + + if (acc.ok && transformedKey.ok && transformedValue.ok) { + return { + ok: true, + value: { + ...acc.value, + [transformedKey.value]: transformedValue.value, + }, + }; + } + + const errors: ValidationError[] = []; + if (!acc.ok) { + errors.push(...acc.errors); + } + if (!transformedKey.ok) { + errors.push(...transformedKey.errors); + } + if (!transformedValue.ok) { + errors.push(...transformedValue.errors); + } + + return { + ok: false, + errors, + }; + }, + Promise.resolve({ ok: true, value: {} as Record }) + ); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/types.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/types.ts new file mode 100644 index 00000000000..eb82cc7f65c --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/record/types.ts @@ -0,0 +1,17 @@ +import { BaseSchema } from "../../Schema"; +import { SchemaUtils } from "../schema-utils"; + +export type RecordSchema< + RawKey extends string | number, + RawValue, + ParsedKey extends string | number, + ParsedValue +> = BaseRecordSchema & + SchemaUtils, Record>; + +export type BaseRecordSchema< + RawKey extends string | number, + RawValue, + ParsedKey extends string | number, + ParsedValue +> = BaseSchema, Record>; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/JsonError.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/JsonError.ts new file mode 100644 index 00000000000..2b89ca0e7ad --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/JsonError.ts @@ -0,0 +1,9 @@ +import { ValidationError } from "../../Schema"; +import { stringifyValidationError } from "./stringifyValidationErrors"; + +export class JsonError extends Error { + constructor(public readonly errors: ValidationError[]) { + super(errors.map(stringifyValidationError).join("; ")); + Object.setPrototypeOf(this, JsonError.prototype); + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/ParseError.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/ParseError.ts new file mode 100644 index 00000000000..d056eb45cf7 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/ParseError.ts @@ -0,0 +1,9 @@ +import { ValidationError } from "../../Schema"; +import { stringifyValidationError } from "./stringifyValidationErrors"; + +export class ParseError extends Error { + constructor(public readonly errors: ValidationError[]) { + super(errors.map(stringifyValidationError).join("; ")); + Object.setPrototypeOf(this, ParseError.prototype); + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/getSchemaUtils.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/getSchemaUtils.ts new file mode 100644 index 00000000000..0c0d379d800 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/getSchemaUtils.ts @@ -0,0 +1,99 @@ +import { BaseSchema, Schema, SchemaOptions, SchemaType } from "../../Schema"; +import { JsonError } from "./JsonError"; +import { ParseError } from "./ParseError"; + +export interface SchemaUtils { + optional: () => Schema; + transform: (transformer: SchemaTransformer) => Schema; + parseOrThrow: (raw: unknown, opts?: SchemaOptions) => Promise; + jsonOrThrow: (raw: unknown, opts?: SchemaOptions) => Promise; +} + +export interface SchemaTransformer { + transform: (parsed: Parsed) => Transformed; + untransform: (transformed: any) => Parsed; +} + +export function getSchemaUtils(schema: BaseSchema): SchemaUtils { + return { + optional: () => optional(schema), + transform: (transformer) => transform(schema, transformer), + parseOrThrow: async (raw, opts) => { + const parsed = await schema.parse(raw, opts); + if (parsed.ok) { + return parsed.value; + } + throw new ParseError(parsed.errors); + }, + jsonOrThrow: async (parsed, opts) => { + const raw = await schema.json(parsed, opts); + if (raw.ok) { + return raw.value; + } + throw new JsonError(raw.errors); + }, + }; +} + +/** + * schema utils are defined in one file to resolve issues with circular imports + */ + +export function optional( + schema: BaseSchema +): Schema { + const baseSchema: BaseSchema = { + parse: (raw, opts) => { + if (raw == null) { + return { + ok: true, + value: undefined, + }; + } + return schema.parse(raw, opts); + }, + json: (parsed, opts) => { + if (parsed == null) { + return { + ok: true, + value: null, + }; + } + return schema.json(parsed, opts); + }, + getType: () => SchemaType.OPTIONAL, + }; + + return { + ...baseSchema, + ...getSchemaUtils(baseSchema), + }; +} + +export function transform( + schema: BaseSchema, + transformer: SchemaTransformer +): Schema { + const baseSchema: BaseSchema = { + parse: async (raw, opts) => { + const parsed = await schema.parse(raw, opts); + if (!parsed.ok) { + return parsed; + } + return { + ok: true, + value: transformer.transform(parsed.value), + }; + }, + json: async (transformed, opts) => { + const parsed = await transformer.untransform(transformed); + return schema.json(parsed, opts); + }, + getType: () => schema.getType(), + }; + + return { + ...baseSchema, + ...getSchemaUtils(baseSchema), + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/index.ts new file mode 100644 index 00000000000..aa04e051dfa --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/index.ts @@ -0,0 +1,4 @@ +export { getSchemaUtils, optional, transform } from "./getSchemaUtils"; +export type { SchemaUtils } from "./getSchemaUtils"; +export { JsonError } from "./JsonError"; +export { ParseError } from "./ParseError"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/stringifyValidationErrors.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/stringifyValidationErrors.ts new file mode 100644 index 00000000000..4160f0a2617 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/schema-utils/stringifyValidationErrors.ts @@ -0,0 +1,8 @@ +import { ValidationError } from "../../Schema"; + +export function stringifyValidationError(error: ValidationError): string { + if (error.path.length === 0) { + return error.message; + } + return `${error.path.join(" -> ")}: ${error.message}`; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/index.ts new file mode 100644 index 00000000000..f3310e8bdad --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/index.ts @@ -0,0 +1 @@ +export { set } from "./set"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/set.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/set.ts new file mode 100644 index 00000000000..3113bcba307 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/set/set.ts @@ -0,0 +1,43 @@ +import { BaseSchema, Schema, SchemaType } from "../../Schema"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { list } from "../list"; +import { getSchemaUtils } from "../schema-utils"; + +export function set(schema: Schema): Schema> { + const listSchema = list(schema); + const baseSchema: BaseSchema> = { + parse: async (raw, opts) => { + const parsedList = await listSchema.parse(raw, opts); + if (parsedList.ok) { + return { + ok: true, + value: new Set(parsedList.value), + }; + } else { + return parsedList; + } + }, + json: async (parsed, opts) => { + if (!(parsed instanceof Set)) { + return { + ok: false, + errors: [ + { + path: opts?.breadcrumbsPrefix ?? [], + message: getErrorMessageForIncorrectType(parsed, "Set"), + }, + ], + }; + } + const jsonList = await listSchema.json([...parsed], opts); + return jsonList; + }, + getType: () => SchemaType.SET, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/index.ts new file mode 100644 index 00000000000..75b71cb3565 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/index.ts @@ -0,0 +1,6 @@ +export type { + inferParsedUnidiscriminatedUnionSchema, + inferRawUnidiscriminatedUnionSchema, + UndiscriminatedUnionSchema, +} from "./types"; +export { undiscriminatedUnion } from "./undiscriminatedUnion"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/types.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/types.ts new file mode 100644 index 00000000000..43e7108a060 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/types.ts @@ -0,0 +1,10 @@ +import { inferParsed, inferRaw, Schema } from "../../Schema"; + +export type UndiscriminatedUnionSchema = Schema< + inferRawUnidiscriminatedUnionSchema, + inferParsedUnidiscriminatedUnionSchema +>; + +export type inferRawUnidiscriminatedUnionSchema = inferRaw; + +export type inferParsedUnidiscriminatedUnionSchema = inferParsed; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/undiscriminatedUnion.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/undiscriminatedUnion.ts new file mode 100644 index 00000000000..771dc6a7efa --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/undiscriminated-union/undiscriminatedUnion.ts @@ -0,0 +1,61 @@ +import { BaseSchema, MaybeValid, Schema, SchemaOptions, SchemaType, ValidationError } from "../../Schema"; +import { MaybePromise } from "../../utils/MaybePromise"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { getSchemaUtils } from "../schema-utils"; +import { inferParsedUnidiscriminatedUnionSchema, inferRawUnidiscriminatedUnionSchema } from "./types"; + +export function undiscriminatedUnion, ...Schema[]]>( + schemas: Schemas +): Schema, inferParsedUnidiscriminatedUnionSchema> { + const baseSchema: BaseSchema< + inferRawUnidiscriminatedUnionSchema, + inferParsedUnidiscriminatedUnionSchema + > = { + parse: async (raw, opts) => { + return validateAndTransformUndiscriminatedUnion>( + (schema, opts) => schema.parse(raw, opts), + schemas, + opts + ); + }, + json: async (parsed, opts) => { + return validateAndTransformUndiscriminatedUnion>( + (schema, opts) => schema.json(parsed, opts), + schemas, + opts + ); + }, + getType: () => SchemaType.UNDISCRIMINATED_UNION, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; +} + +async function validateAndTransformUndiscriminatedUnion( + transform: (schema: Schema, opts: SchemaOptions) => MaybePromise>, + schemas: Schema[], + opts: SchemaOptions | undefined +): Promise> { + const errors: ValidationError[] = []; + for (const [index, schema] of schemas.entries()) { + const transformed = await transform(schema, { ...opts, skipValidation: false }); + if (transformed.ok) { + return transformed; + } else { + for (const error of transformed.errors) { + errors.push({ + path: error.path, + message: `[Variant ${index}] ${error.message}`, + }); + } + } + } + + return { + ok: false, + errors, + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/discriminant.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/discriminant.ts new file mode 100644 index 00000000000..55065bc8946 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/discriminant.ts @@ -0,0 +1,14 @@ +export function discriminant( + parsedDiscriminant: ParsedDiscriminant, + rawDiscriminant: RawDiscriminant +): Discriminant { + return { + parsedDiscriminant, + rawDiscriminant, + }; +} + +export interface Discriminant { + parsedDiscriminant: ParsedDiscriminant; + rawDiscriminant: RawDiscriminant; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/index.ts new file mode 100644 index 00000000000..85fc008a2d8 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/index.ts @@ -0,0 +1,10 @@ +export { discriminant } from "./discriminant"; +export type { Discriminant } from "./discriminant"; +export type { + inferParsedDiscriminant, + inferParsedUnion, + inferRawDiscriminant, + inferRawUnion, + UnionSubtypes, +} from "./types"; +export { union } from "./union"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/types.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/types.ts new file mode 100644 index 00000000000..6f82c868b2d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/types.ts @@ -0,0 +1,26 @@ +import { inferParsedObject, inferRawObject, ObjectSchema } from "../object"; +import { Discriminant } from "./discriminant"; + +export type UnionSubtypes = { + [K in DiscriminantValues]: ObjectSchema; +}; + +export type inferRawUnion, U extends UnionSubtypes> = { + [K in keyof U]: Record, K> & inferRawObject; +}[keyof U]; + +export type inferParsedUnion, U extends UnionSubtypes> = { + [K in keyof U]: Record, K> & inferParsedObject; +}[keyof U]; + +export type inferRawDiscriminant> = D extends string + ? D + : D extends Discriminant + ? Raw + : never; + +export type inferParsedDiscriminant> = D extends string + ? D + : D extends Discriminant + ? Parsed + : never; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/union.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/union.ts new file mode 100644 index 00000000000..ed659beb62d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/builders/union/union.ts @@ -0,0 +1,173 @@ +import { BaseSchema, MaybeValid, SchemaType } from "../../Schema"; +import { getErrorMessageForIncorrectType } from "../../utils/getErrorMessageForIncorrectType"; +import { isPlainObject } from "../../utils/isPlainObject"; +import { keys } from "../../utils/keys"; +import { MaybePromise } from "../../utils/MaybePromise"; +import { maybeSkipValidation } from "../../utils/maybeSkipValidation"; +import { enum_ } from "../enum"; +import { ObjectSchema } from "../object"; +import { getObjectLikeUtils, ObjectLikeSchema } from "../object-like"; +import { getSchemaUtils } from "../schema-utils"; +import { Discriminant } from "./discriminant"; +import { inferParsedDiscriminant, inferParsedUnion, inferRawDiscriminant, inferRawUnion, UnionSubtypes } from "./types"; + +export function union, U extends UnionSubtypes>( + discriminant: D, + union: U +): ObjectLikeSchema, inferParsedUnion> { + const rawDiscriminant = + typeof discriminant === "string" ? discriminant : (discriminant.rawDiscriminant as inferRawDiscriminant); + const parsedDiscriminant = + typeof discriminant === "string" + ? discriminant + : (discriminant.parsedDiscriminant as inferParsedDiscriminant); + + const discriminantValueSchema = enum_(keys(union) as string[]); + + const baseSchema: BaseSchema, inferParsedUnion> = { + parse: async (raw, opts) => { + return transformAndValidateUnion({ + value: raw, + discriminant: rawDiscriminant, + transformedDiscriminant: parsedDiscriminant, + transformDiscriminantValue: (discriminantValue) => + discriminantValueSchema.parse(discriminantValue, { + allowUnrecognizedEnumValues: opts?.allowUnrecognizedUnionMembers, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), rawDiscriminant], + }), + getAdditionalPropertiesSchema: (discriminantValue) => union[discriminantValue], + allowUnrecognizedUnionMembers: opts?.allowUnrecognizedUnionMembers, + transformAdditionalProperties: (additionalProperties, additionalPropertiesSchema) => + additionalPropertiesSchema.parse(additionalProperties, opts), + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + json: async (parsed, opts) => { + return transformAndValidateUnion({ + value: parsed, + discriminant: parsedDiscriminant, + transformedDiscriminant: rawDiscriminant, + transformDiscriminantValue: (discriminantValue) => + discriminantValueSchema.json(discriminantValue, { + allowUnrecognizedEnumValues: opts?.allowUnrecognizedUnionMembers, + breadcrumbsPrefix: [...(opts?.breadcrumbsPrefix ?? []), parsedDiscriminant], + }), + getAdditionalPropertiesSchema: (discriminantValue) => union[discriminantValue], + allowUnrecognizedUnionMembers: opts?.allowUnrecognizedUnionMembers, + transformAdditionalProperties: (additionalProperties, additionalPropertiesSchema) => + additionalPropertiesSchema.json(additionalProperties, opts), + breadcrumbsPrefix: opts?.breadcrumbsPrefix, + }); + }, + getType: () => SchemaType.UNION, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + ...getObjectLikeUtils(baseSchema), + }; +} + +async function transformAndValidateUnion< + TransformedDiscriminant extends string, + TransformedDiscriminantValue extends string, + TransformedAdditionalProperties +>({ + value, + discriminant, + transformedDiscriminant, + transformDiscriminantValue, + getAdditionalPropertiesSchema, + allowUnrecognizedUnionMembers = false, + transformAdditionalProperties, + breadcrumbsPrefix = [], +}: { + value: unknown; + discriminant: string; + transformedDiscriminant: TransformedDiscriminant; + transformDiscriminantValue: (discriminantValue: unknown) => MaybePromise>; + getAdditionalPropertiesSchema: (discriminantValue: string) => ObjectSchema | undefined; + allowUnrecognizedUnionMembers: boolean | undefined; + transformAdditionalProperties: ( + additionalProperties: unknown, + additionalPropertiesSchema: ObjectSchema + ) => MaybePromise>; + breadcrumbsPrefix: string[] | undefined; +}): Promise< + MaybeValid & TransformedAdditionalProperties> +> { + if (!isPlainObject(value)) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: getErrorMessageForIncorrectType(value, "object"), + }, + ], + }; + } + + const { [discriminant]: discriminantValue, ...additionalProperties } = value; + + if (discriminantValue == null) { + return { + ok: false, + errors: [ + { + path: breadcrumbsPrefix, + message: `Missing discriminant ("${discriminant}")`, + }, + ], + }; + } + + const transformedDiscriminantValue = await transformDiscriminantValue(discriminantValue); + if (!transformedDiscriminantValue.ok) { + return { + ok: false, + errors: transformedDiscriminantValue.errors, + }; + } + + const additionalPropertiesSchema = getAdditionalPropertiesSchema(transformedDiscriminantValue.value); + + if (additionalPropertiesSchema == null) { + if (allowUnrecognizedUnionMembers) { + return { + ok: true, + value: { + [transformedDiscriminant]: transformedDiscriminantValue.value, + ...additionalProperties, + } as Record & TransformedAdditionalProperties, + }; + } else { + return { + ok: false, + errors: [ + { + path: [...breadcrumbsPrefix, discriminant], + message: "Unexpected discriminant value", + }, + ], + }; + } + } + + const transformedAdditionalProperties = await transformAdditionalProperties( + additionalProperties, + additionalPropertiesSchema + ); + if (!transformedAdditionalProperties.ok) { + return transformedAdditionalProperties; + } + + return { + ok: true, + value: { + [transformedDiscriminant]: discriminantValue, + ...transformedAdditionalProperties.value, + } as Record & TransformedAdditionalProperties, + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/index.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/index.ts new file mode 100644 index 00000000000..5429d8b43eb --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/index.ts @@ -0,0 +1,2 @@ +export * from "./builders"; +export type { inferParsed, inferRaw, Schema, SchemaOptions } from "./Schema"; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/MaybePromise.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/MaybePromise.ts new file mode 100644 index 00000000000..9cd354b3418 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/MaybePromise.ts @@ -0,0 +1 @@ +export type MaybePromise = T | Promise; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/addQuestionMarksToNullableProperties.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/addQuestionMarksToNullableProperties.ts new file mode 100644 index 00000000000..4111d703cd0 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/addQuestionMarksToNullableProperties.ts @@ -0,0 +1,15 @@ +export type addQuestionMarksToNullableProperties = { + [K in OptionalKeys]?: T[K]; +} & Pick>; + +export type OptionalKeys = { + [K in keyof T]-?: undefined extends T[K] + ? K + : null extends T[K] + ? K + : 1 extends (any extends T[K] ? 0 : 1) + ? never + : K; +}[keyof T]; + +export type RequiredKeys = Exclude>; diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/createIdentitySchemaCreator.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/createIdentitySchemaCreator.ts new file mode 100644 index 00000000000..de107cf5ee1 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/createIdentitySchemaCreator.ts @@ -0,0 +1,21 @@ +import { getSchemaUtils } from "../builders/schema-utils"; +import { BaseSchema, MaybeValid, Schema, SchemaOptions, SchemaType } from "../Schema"; +import { maybeSkipValidation } from "./maybeSkipValidation"; + +export function createIdentitySchemaCreator( + schemaType: SchemaType, + validate: (value: unknown, opts?: SchemaOptions) => MaybeValid +): () => Schema { + return () => { + const baseSchema: BaseSchema = { + parse: validate, + json: validate, + getType: () => schemaType, + }; + + return { + ...maybeSkipValidation(baseSchema), + ...getSchemaUtils(baseSchema), + }; + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/entries.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/entries.ts new file mode 100644 index 00000000000..e122952137d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/entries.ts @@ -0,0 +1,3 @@ +export function entries(object: T): [keyof T, T[keyof T]][] { + return Object.entries(object) as [keyof T, T[keyof T]][]; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/filterObject.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/filterObject.ts new file mode 100644 index 00000000000..2c25a3455bc --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/filterObject.ts @@ -0,0 +1,10 @@ +export function filterObject(obj: T, keysToInclude: K[]): Pick { + const keysToIncludeSet = new Set(keysToInclude); + return Object.entries(obj).reduce((acc, [key, value]) => { + if (keysToIncludeSet.has(key as K)) { + acc[key as K] = value; + } + return acc; + // eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter + }, {} as Pick); +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/getErrorMessageForIncorrectType.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/getErrorMessageForIncorrectType.ts new file mode 100644 index 00000000000..438012df418 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/getErrorMessageForIncorrectType.ts @@ -0,0 +1,21 @@ +export function getErrorMessageForIncorrectType(value: unknown, expectedType: string): string { + return `Expected ${expectedType}. Received ${getTypeAsString(value)}.`; +} + +function getTypeAsString(value: unknown): string { + if (Array.isArray(value)) { + return "list"; + } + if (value === null) { + return "null"; + } + switch (typeof value) { + case "string": + return `"${value}"`; + case "number": + case "boolean": + case "undefined": + return `${value}`; + } + return typeof value; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/isPlainObject.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/isPlainObject.ts new file mode 100644 index 00000000000..db82a722c35 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/isPlainObject.ts @@ -0,0 +1,17 @@ +// borrowed from https://github.com/lodash/lodash/blob/master/isPlainObject.js +export function isPlainObject(value: unknown): value is Record { + if (typeof value !== "object" || value === null) { + return false; + } + + if (Object.getPrototypeOf(value) === null) { + return true; + } + + let proto = value; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + + return Object.getPrototypeOf(value) === proto; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/keys.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/keys.ts new file mode 100644 index 00000000000..01867098287 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/keys.ts @@ -0,0 +1,3 @@ +export function keys(object: T): (keyof T)[] { + return Object.keys(object) as (keyof T)[]; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/maybeSkipValidation.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/maybeSkipValidation.ts new file mode 100644 index 00000000000..99c02c32bda --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/maybeSkipValidation.ts @@ -0,0 +1,39 @@ +import { BaseSchema, MaybeValid, SchemaOptions } from "../Schema"; +import { MaybePromise } from "./MaybePromise"; + +export function maybeSkipValidation, Raw, Parsed>(schema: S): S { + return { + ...schema, + json: transformAndMaybeSkipValidation(schema.json), + parse: transformAndMaybeSkipValidation(schema.parse), + }; +} + +function transformAndMaybeSkipValidation( + transform: (value: unknown, opts?: SchemaOptions) => MaybePromise> +): (value: unknown, opts?: SchemaOptions) => MaybePromise> { + return async (value, opts): Promise> => { + const transformed = await transform(value, opts); + const { skipValidation = false } = opts ?? {}; + if (!transformed.ok && skipValidation) { + // eslint-disable-next-line no-console + console.warn( + [ + "Failed to validate.", + ...transformed.errors.map( + (error) => + " - " + + (error.path.length > 0 ? `${error.path.join(".")}: ${error.message}` : error.message) + ), + ].join("\n") + ); + + return { + ok: true, + value: value as T, + }; + } else { + return transformed; + } + }; +} diff --git a/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/partition.ts b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/partition.ts new file mode 100644 index 00000000000..f58d6f3d35f --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/core/schemas/utils/partition.ts @@ -0,0 +1,12 @@ +export function partition(items: readonly T[], predicate: (item: T) => boolean): [T[], T[]] { + const trueItems: T[] = [], + falseItems: T[] = []; + for (const item of items) { + if (predicate(item)) { + trueItems.push(item); + } else { + falseItems.push(item); + } + } + return [trueItems, falseItems]; +} diff --git a/seed/ts-express/oauth-client-credentials-default/errors/SeedOauthClientCredentialsDefaultError.ts b/seed/ts-express/oauth-client-credentials-default/errors/SeedOauthClientCredentialsDefaultError.ts new file mode 100644 index 00000000000..e7d4a64405d --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/errors/SeedOauthClientCredentialsDefaultError.ts @@ -0,0 +1,14 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import express from "express"; + +export abstract class SeedOauthClientCredentialsDefaultError extends Error { + constructor(public readonly errorName?: string) { + super(); + Object.setPrototypeOf(this, SeedOauthClientCredentialsDefaultError.prototype); + } + + public abstract send(res: express.Response): Promise; +} diff --git a/seed/ts-express/oauth-client-credentials-default/errors/index.ts b/seed/ts-express/oauth-client-credentials-default/errors/index.ts new file mode 100644 index 00000000000..1b6de2104cd --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/errors/index.ts @@ -0,0 +1 @@ +export { SeedOauthClientCredentialsDefaultError } from "./SeedOauthClientCredentialsDefaultError"; diff --git a/seed/ts-express/oauth-client-credentials-default/index.ts b/seed/ts-express/oauth-client-credentials-default/index.ts new file mode 100644 index 00000000000..21dddb213e6 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/index.ts @@ -0,0 +1,3 @@ +export * as SeedOauthClientCredentialsDefault from "./api"; +export { register } from "./register"; +export { SeedOauthClientCredentialsDefaultError } from "./errors"; diff --git a/seed/ts-express/oauth-client-credentials-default/register.ts b/seed/ts-express/oauth-client-credentials-default/register.ts new file mode 100644 index 00000000000..31a60ca7bac --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/register.ts @@ -0,0 +1,15 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import express from "express"; +import { AuthService } from "./api/resources/auth/service/AuthService"; + +export function register( + expressApp: express.Express | express.Router, + services: { + auth: AuthService; + } +): void { + (expressApp as any).use("/", services.auth.toRouter()); +} diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/index.ts new file mode 100644 index 00000000000..3e5335fe421 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/index.ts @@ -0,0 +1 @@ +export * from "./resources"; diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/index.ts new file mode 100644 index 00000000000..fcc81debec4 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./types"; +export * from "./service"; diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/index.ts new file mode 100644 index 00000000000..415726b7fea --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/index.ts @@ -0,0 +1 @@ +export * from "./requests"; diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/GetTokenRequest.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/GetTokenRequest.ts new file mode 100644 index 00000000000..05bef652f27 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/GetTokenRequest.ts @@ -0,0 +1,24 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as serializers from "../../../../index"; +import * as SeedOauthClientCredentialsDefault from "../../../../../api/index"; +import * as core from "../../../../../core"; + +export const GetTokenRequest: core.serialization.Schema< + serializers.GetTokenRequest.Raw, + SeedOauthClientCredentialsDefault.GetTokenRequest +> = core.serialization.object({ + clientId: core.serialization.property("client_id", core.serialization.string()), + clientSecret: core.serialization.property("client_secret", core.serialization.string()), + grantType: core.serialization.property("grant_type", core.serialization.stringLiteral("client_credentials")), +}); + +export declare namespace GetTokenRequest { + interface Raw { + client_id: string; + client_secret: string; + grant_type: "client_credentials"; + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/index.ts new file mode 100644 index 00000000000..c890bee6072 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/service/requests/index.ts @@ -0,0 +1 @@ +export { GetTokenRequest } from "./GetTokenRequest"; diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/TokenResponse.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/TokenResponse.ts new file mode 100644 index 00000000000..47c972b8e2e --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/TokenResponse.ts @@ -0,0 +1,22 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as serializers from "../../../index"; +import * as SeedOauthClientCredentialsDefault from "../../../../api/index"; +import * as core from "../../../../core"; + +export const TokenResponse: core.serialization.ObjectSchema< + serializers.TokenResponse.Raw, + SeedOauthClientCredentialsDefault.TokenResponse +> = core.serialization.object({ + accessToken: core.serialization.property("access_token", core.serialization.string()), + expiresIn: core.serialization.property("expires_in", core.serialization.number()), +}); + +export declare namespace TokenResponse { + interface Raw { + access_token: string; + expires_in: number; + } +} diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/index.ts new file mode 100644 index 00000000000..6848a730c91 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/auth/types/index.ts @@ -0,0 +1 @@ +export * from "./TokenResponse"; diff --git a/seed/ts-express/oauth-client-credentials-default/serialization/resources/index.ts b/seed/ts-express/oauth-client-credentials-default/serialization/resources/index.ts new file mode 100644 index 00000000000..f6dde5f4e87 --- /dev/null +++ b/seed/ts-express/oauth-client-credentials-default/serialization/resources/index.ts @@ -0,0 +1,3 @@ +export * as auth from "./auth"; +export * from "./auth/types"; +export * from "./auth/service/requests"; diff --git a/seed/ts-express/oauth-client-credentials-default/snippet-templates.json b/seed/ts-express/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ts-express/oauth-client-credentials-default/snippet.json b/seed/ts-express/oauth-client-credentials-default/snippet.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ts-sdk/oauth-client-credentials-default/.inputs/config.json b/seed/ts-sdk/oauth-client-credentials-default/.inputs/config.json new file mode 100644 index 00000000000..95a9fda95ad --- /dev/null +++ b/seed/ts-sdk/oauth-client-credentials-default/.inputs/config.json @@ -0,0 +1,29 @@ +{ + "irFilepath": "/fern/ir.json", + "output": { + "mode": { + "type": "github", + "repoUrl": "https://github.com/oauth-client-credentials-default/fern", + "version": "0.0.1", + "publishInfo": { + "type": "npm", + "registryUrl": "", + "packageName": "@fern/oauth-client-credentials-default", + "tokenEnvironmentVariable": "" + } + }, + "path": "/fern/output", + "publishingMetadata": null, + "snippetFilepath": "/fern/snippet.json" + }, + "publish": null, + "workspaceName": "oauth-client-credentials-default", + "organization": "seed", + "environment": { + "_type": "local" + }, + "dryRun": false, + "whitelabel": false, + "writeUnitTests": true, + "generateOauthClients": true +} \ No newline at end of file diff --git a/seed/ts-sdk/oauth-client-credentials-default/.inputs/ir.json b/seed/ts-sdk/oauth-client-credentials-default/.inputs/ir.json new file mode 100644 index 00000000000..ed3c996cde7 --- /dev/null +++ b/seed/ts-sdk/oauth-client-credentials-default/.inputs/ir.json @@ -0,0 +1,1223 @@ +{ + "apiName": { + "originalName": "oauth-client-credentials-default", + "camelCase": { + "unsafeName": "oauthClientCredentialsDefault", + "safeName": "oauthClientCredentialsDefault" + }, + "snakeCase": { + "unsafeName": "oauth_client_credentials_default", + "safeName": "oauth_client_credentials_default" + }, + "screamingSnakeCase": { + "unsafeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT", + "safeName": "OAUTH_CLIENT_CREDENTIALS_DEFAULT" + }, + "pascalCase": { + "unsafeName": "OauthClientCredentialsDefault", + "safeName": "OauthClientCredentialsDefault" + } + }, + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [ + { + "_type": "oauth", + "configuration": { + "type": "clientCredentials", + "clientIdEnvVar": null, + "clientSecretEnvVar": null, + "tokenPrefix": null, + "scopes": null, + "tokenEndpoint": { + "endpointReference": { + "endpointId": "endpoint_auth.getToken", + "serviceId": "service_auth", + "subpackageId": "subpackage_auth" + }, + "requestProperties": { + "clientId": { + "propertyPath": [], + "property": { + "type": "body", + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "clientSecret": { + "propertyPath": [], + "property": { + "type": "body", + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "scopes": null + }, + "responseProperties": { + "accessToken": { + "propertyPath": [], + "property": { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + } + }, + "expiresIn": null, + "refreshToken": null + } + }, + "refreshEndpoint": null + }, + "docs": null + } + ], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_auth:TokenResponse": { + "name": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "availability": null, + "docs": null + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "valueType": { + "_type": "primitive", + "primitive": "INTEGER" + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false + }, + "referencedTypes": [], + "examples": [], + "availability": null, + "docs": "An OAuth token response." + } + }, + "errors": {}, + "services": { + "service_auth": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "endpoints": [ + { + "id": "endpoint_auth.getToken", + "name": { + "originalName": "getToken", + "camelCase": { + "unsafeName": "getToken", + "safeName": "getToken" + }, + "snakeCase": { + "unsafeName": "get_token", + "safeName": "get_token" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN", + "safeName": "GET_TOKEN" + }, + "pascalCase": { + "unsafeName": "GetToken", + "safeName": "GetToken" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/token", + "parts": [] + }, + "fullPath": { + "head": "/token", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "inlinedRequestBody", + "name": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "extends": [], + "contentType": null, + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "valueType": { + "_type": "primitive", + "primitive": "STRING" + }, + "docs": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "client_credentials" + } + } + }, + "docs": null + } + ], + "extra-properties": false + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "GetTokenRequest", + "camelCase": { + "unsafeName": "getTokenRequest", + "safeName": "getTokenRequest" + }, + "snakeCase": { + "unsafeName": "get_token_request", + "safeName": "get_token_request" + }, + "screamingSnakeCase": { + "unsafeName": "GET_TOKEN_REQUEST", + "safeName": "GET_TOKEN_REQUEST" + }, + "pascalCase": { + "unsafeName": "GetTokenRequest", + "safeName": "GetTokenRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + } + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "docs": null + } + }, + "status-code": null + }, + "errors": [], + "examples": [ + { + "exampleType": "generated", + "url": "/token", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": { + "name": { + "originalName": "client_id", + "camelCase": { + "unsafeName": "clientId", + "safeName": "clientId" + }, + "snakeCase": { + "unsafeName": "client_id", + "safeName": "client_id" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_ID", + "safeName": "CLIENT_ID" + }, + "pascalCase": { + "unsafeName": "ClientId", + "safeName": "ClientId" + } + }, + "wireValue": "client_id" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "client_secret", + "camelCase": { + "unsafeName": "clientSecret", + "safeName": "clientSecret" + }, + "snakeCase": { + "unsafeName": "client_secret", + "safeName": "client_secret" + }, + "screamingSnakeCase": { + "unsafeName": "CLIENT_SECRET", + "safeName": "CLIENT_SECRET" + }, + "pascalCase": { + "unsafeName": "ClientSecret", + "safeName": "ClientSecret" + } + }, + "wireValue": "client_secret" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": null + }, + { + "name": { + "name": { + "originalName": "grant_type", + "camelCase": { + "unsafeName": "grantType", + "safeName": "grantType" + }, + "snakeCase": { + "unsafeName": "grant_type", + "safeName": "grant_type" + }, + "screamingSnakeCase": { + "unsafeName": "GRANT_TYPE", + "safeName": "GRANT_TYPE" + }, + "pascalCase": { + "unsafeName": "GrantType", + "safeName": "GrantType" + } + }, + "wireValue": "grant_type" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "client_credentials" + } + } + }, + "jsonExample": "\"client_credentials\"" + }, + "originalTypeDeclaration": null + } + ], + "jsonExample": { + "client_id": "string", + "client_secret": "string", + "grant_type": "\"client_credentials\"" + } + }, + "name": null, + "codeSamples": null, + "response": { + "type": "ok", + "body": { + "shape": { + "type": "named", + "typeName": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + }, + "shape": { + "type": "object", + "properties": [ + { + "name": { + "name": { + "originalName": "access_token", + "camelCase": { + "unsafeName": "accessToken", + "safeName": "accessToken" + }, + "snakeCase": { + "unsafeName": "access_token", + "safeName": "access_token" + }, + "screamingSnakeCase": { + "unsafeName": "ACCESS_TOKEN", + "safeName": "ACCESS_TOKEN" + }, + "pascalCase": { + "unsafeName": "AccessToken", + "safeName": "AccessToken" + } + }, + "wireValue": "access_token" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + }, + { + "name": { + "name": { + "originalName": "expires_in", + "camelCase": { + "unsafeName": "expiresIn", + "safeName": "expiresIn" + }, + "snakeCase": { + "unsafeName": "expires_in", + "safeName": "expires_in" + }, + "screamingSnakeCase": { + "unsafeName": "EXPIRES_IN", + "safeName": "EXPIRES_IN" + }, + "pascalCase": { + "unsafeName": "ExpiresIn", + "safeName": "ExpiresIn" + } + }, + "wireValue": "expires_in" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "originalTypeDeclaration": { + "name": { + "originalName": "TokenResponse", + "camelCase": { + "unsafeName": "tokenResponse", + "safeName": "tokenResponse" + }, + "snakeCase": { + "unsafeName": "token_response", + "safeName": "token_response" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_RESPONSE", + "safeName": "TOKEN_RESPONSE" + }, + "pascalCase": { + "unsafeName": "TokenResponse", + "safeName": "TokenResponse" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "typeId": "type_auth:TokenResponse" + } + } + ] + } + }, + "jsonExample": { + "access_token": "string", + "expires_in": 1 + } + } + }, + "docs": null + } + ], + "pagination": null, + "availability": null, + "docs": null + } + ] + } + }, + "constants": { + "errorInstanceIdKey": { + "name": { + "originalName": "errorInstanceId", + "camelCase": { + "unsafeName": "errorInstanceId", + "safeName": "errorInstanceId" + }, + "snakeCase": { + "unsafeName": "error_instance_id", + "safeName": "error_instance_id" + }, + "screamingSnakeCase": { + "unsafeName": "ERROR_INSTANCE_ID", + "safeName": "ERROR_INSTANCE_ID" + }, + "pascalCase": { + "unsafeName": "ErrorInstanceId", + "safeName": "ErrorInstanceId" + } + }, + "wireValue": "errorInstanceId" + } + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_auth": [ + "type_auth:TokenResponse" + ] + }, + "sharedTypes": [] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "subpackages": { + "subpackage_auth": { + "name": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + ], + "packagePath": [], + "file": { + "originalName": "auth", + "camelCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "snakeCase": { + "unsafeName": "auth", + "safeName": "auth" + }, + "screamingSnakeCase": { + "unsafeName": "AUTH", + "safeName": "AUTH" + }, + "pascalCase": { + "unsafeName": "Auth", + "safeName": "Auth" + } + } + }, + "service": "service_auth", + "types": [ + "type_auth:TokenResponse" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": null, + "hasEndpointsInTree": true, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_auth" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": true, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version" + } + } +} \ No newline at end of file From 3416b17376825200f1b969890403b88e564b6b12 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 9 May 2024 12:41:51 -0400 Subject: [PATCH 5/6] Update seed configuration --- seed/python-sdk/seed.yml | 1 + ...n_oauth_client_credentials_default.gemspec | 4 + .../fern_oauth_client_credentials_default.rb | 46 +++++- .../auth/client.rb | 73 +++++++++ .../lib/requests.rb | 148 ++++++++++++++++++ .../lib/types_export.rb | 3 + .../snippet.json | 4 + seed/ts-sdk/seed.yml | 1 + 8 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/client.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/requests.rb create mode 100644 seed/ruby-sdk/oauth-client-credentials-default/lib/types_export.rb diff --git a/seed/python-sdk/seed.yml b/seed/python-sdk/seed.yml index adcde348ec1..51cca3defc0 100644 --- a/seed/python-sdk/seed.yml +++ b/seed/python-sdk/seed.yml @@ -92,3 +92,4 @@ allowedFailures: - extra-properties - trace - circular-references-advanced + - oauth-client-credentials-default diff --git a/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec b/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec index b8c813b3454..34e2b14125b 100644 --- a/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec +++ b/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec @@ -18,4 +18,8 @@ Gem::Specification.new do |spec| spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] + spec.add_dependency "async-http-faraday", ">= 0.0", "< 1.0" + spec.add_dependency "faraday", ">= 1.10", "< 3.0" + spec.add_dependency "faraday-net_http", ">= 1.0", "< 4.0" + spec.add_dependency "faraday-retry", ">= 1.0", "< 3.0" end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb index 7fb344e044f..6b815a96a6e 100644 --- a/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb @@ -1,3 +1,47 @@ # frozen_string_literal: true -require_relative "fern_oauth_client_credentials_default/auth/types/token_response" +require_relative "types_export" +require_relative "requests" +require_relative "fern_oauth_client_credentials_default/auth/client" + +module SeedOauthClientCredentialsDefaultClient + class Client + # @return [SeedOauthClientCredentialsDefaultClient::AuthClient] + attr_reader :auth + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @param token [String] + # @return [SeedOauthClientCredentialsDefaultClient::Client] + def initialize(token:, base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @request_client = SeedOauthClientCredentialsDefaultClient::RequestClient.new( + base_url: base_url, + max_retries: max_retries, + timeout_in_seconds: timeout_in_seconds, + token: token + ) + @auth = SeedOauthClientCredentialsDefaultClient::AuthClient.new(request_client: @request_client) + end + end + + class AsyncClient + # @return [SeedOauthClientCredentialsDefaultClient::AsyncAuthClient] + attr_reader :auth + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @param token [String] + # @return [SeedOauthClientCredentialsDefaultClient::AsyncClient] + def initialize(token:, base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @async_request_client = SeedOauthClientCredentialsDefaultClient::AsyncRequestClient.new( + base_url: base_url, + max_retries: max_retries, + timeout_in_seconds: timeout_in_seconds, + token: token + ) + @auth = SeedOauthClientCredentialsDefaultClient::AsyncAuthClient.new(request_client: @async_request_client) + end + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/client.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/client.rb new file mode 100644 index 00000000000..f086e9433be --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default/auth/client.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require_relative "../../requests" +require_relative "types/token_response" +require "async" + +module SeedOauthClientCredentialsDefaultClient + class AuthClient + # @return [SeedOauthClientCredentialsDefaultClient::RequestClient] + attr_reader :request_client + + # @param request_client [SeedOauthClientCredentialsDefaultClient::RequestClient] + # @return [SeedOauthClientCredentialsDefaultClient::AuthClient] + def initialize(request_client:) + @request_client = request_client + end + + # @param client_id [String] + # @param client_secret [String] + # @param grant_type [String] + # @param request_options [SeedOauthClientCredentialsDefaultClient::RequestOptions] + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def get_token(client_id:, client_secret:, grant_type:, request_options: nil) + response = @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers["Authorization"] = request_options.token unless request_options&.token.nil? + req.headers = { **req.headers, **(request_options&.additional_headers || {}) }.compact + req.body = { + **(request_options&.additional_body_parameters || {}), + client_id: client_id, + client_secret: client_secret, + grant_type: grant_type + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/token" + end + SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse.from_json(json_object: response.body) + end + end + + class AsyncAuthClient + # @return [SeedOauthClientCredentialsDefaultClient::AsyncRequestClient] + attr_reader :request_client + + # @param request_client [SeedOauthClientCredentialsDefaultClient::AsyncRequestClient] + # @return [SeedOauthClientCredentialsDefaultClient::AsyncAuthClient] + def initialize(request_client:) + @request_client = request_client + end + + # @param client_id [String] + # @param client_secret [String] + # @param grant_type [String] + # @param request_options [SeedOauthClientCredentialsDefaultClient::RequestOptions] + # @return [SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse] + def get_token(client_id:, client_secret:, grant_type:, request_options: nil) + Async do + response = @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers["Authorization"] = request_options.token unless request_options&.token.nil? + req.headers = { **req.headers, **(request_options&.additional_headers || {}) }.compact + req.body = { + **(request_options&.additional_body_parameters || {}), + client_id: client_id, + client_secret: client_secret, + grant_type: grant_type + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/token" + end + SeedOauthClientCredentialsDefaultClient::Auth::TokenResponse.from_json(json_object: response.body) + end + end + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/requests.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/requests.rb new file mode 100644 index 00000000000..98eeb45a5ec --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/requests.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require "faraday" +require "faraday/retry" +require "async/http/faraday" + +module SeedOauthClientCredentialsDefaultClient + class RequestClient + # @return [Hash{String => String}] + attr_reader :headers + # @return [Faraday] + attr_reader :conn + # @return [String] + attr_reader :base_url + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @param token [String] + # @return [SeedOauthClientCredentialsDefaultClient::RequestClient] + def initialize(token:, base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @base_url = base_url + @headers = { + "X-Fern-Language": "Ruby", + "X-Fern-SDK-Name": "fern_oauth_client_credentials_default", + "X-Fern-SDK-Version": "0.0.1", + "Authorization": "Bearer #{token}" + } + @conn = Faraday.new(headers: @headers) do |faraday| + faraday.request :json + faraday.response :raise_error, include_request: true + faraday.request :retry, { max: max_retries } unless max_retries.nil? + faraday.options.timeout = timeout_in_seconds unless timeout_in_seconds.nil? + end + end + + # @param request_options [SeedOauthClientCredentialsDefaultClient::RequestOptions] + # @return [String] + def get_url(request_options: nil) + request_options&.base_url || @base_url + end + end + + class AsyncRequestClient + # @return [Hash{String => String}] + attr_reader :headers + # @return [Faraday] + attr_reader :conn + # @return [String] + attr_reader :base_url + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @param token [String] + # @return [SeedOauthClientCredentialsDefaultClient::AsyncRequestClient] + def initialize(token:, base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @base_url = base_url + @headers = { + "X-Fern-Language": "Ruby", + "X-Fern-SDK-Name": "fern_oauth_client_credentials_default", + "X-Fern-SDK-Version": "0.0.1", + "Authorization": "Bearer #{token}" + } + @conn = Faraday.new(headers: @headers) do |faraday| + faraday.request :json + faraday.response :raise_error, include_request: true + faraday.adapter :async_http + faraday.request :retry, { max: max_retries } unless max_retries.nil? + faraday.options.timeout = timeout_in_seconds unless timeout_in_seconds.nil? + end + end + + # @param request_options [SeedOauthClientCredentialsDefaultClient::RequestOptions] + # @return [String] + def get_url(request_options: nil) + request_options&.base_url || @base_url + end + end + + # Additional options for request-specific configuration when calling APIs via the + # SDK. + class RequestOptions + # @return [String] + attr_reader :base_url + # @return [String] + attr_reader :token + # @return [Hash{String => Object}] + attr_reader :additional_headers + # @return [Hash{String => Object}] + attr_reader :additional_query_parameters + # @return [Hash{String => Object}] + attr_reader :additional_body_parameters + # @return [Long] + attr_reader :timeout_in_seconds + + # @param base_url [String] + # @param token [String] + # @param additional_headers [Hash{String => Object}] + # @param additional_query_parameters [Hash{String => Object}] + # @param additional_body_parameters [Hash{String => Object}] + # @param timeout_in_seconds [Long] + # @return [SeedOauthClientCredentialsDefaultClient::RequestOptions] + def initialize(base_url: nil, token: nil, additional_headers: nil, additional_query_parameters: nil, + additional_body_parameters: nil, timeout_in_seconds: nil) + @base_url = base_url + @token = token + @additional_headers = additional_headers + @additional_query_parameters = additional_query_parameters + @additional_body_parameters = additional_body_parameters + @timeout_in_seconds = timeout_in_seconds + end + end + + # Additional options for request-specific configuration when calling APIs via the + # SDK. + class IdempotencyRequestOptions + # @return [String] + attr_reader :base_url + # @return [String] + attr_reader :token + # @return [Hash{String => Object}] + attr_reader :additional_headers + # @return [Hash{String => Object}] + attr_reader :additional_query_parameters + # @return [Hash{String => Object}] + attr_reader :additional_body_parameters + # @return [Long] + attr_reader :timeout_in_seconds + + # @param base_url [String] + # @param token [String] + # @param additional_headers [Hash{String => Object}] + # @param additional_query_parameters [Hash{String => Object}] + # @param additional_body_parameters [Hash{String => Object}] + # @param timeout_in_seconds [Long] + # @return [SeedOauthClientCredentialsDefaultClient::IdempotencyRequestOptions] + def initialize(base_url: nil, token: nil, additional_headers: nil, additional_query_parameters: nil, + additional_body_parameters: nil, timeout_in_seconds: nil) + @base_url = base_url + @token = token + @additional_headers = additional_headers + @additional_query_parameters = additional_query_parameters + @additional_body_parameters = additional_body_parameters + @timeout_in_seconds = timeout_in_seconds + end + end +end diff --git a/seed/ruby-sdk/oauth-client-credentials-default/lib/types_export.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/types_export.rb new file mode 100644 index 00000000000..7fb344e044f --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/types_export.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative "fern_oauth_client_credentials_default/auth/types/token_response" diff --git a/seed/ruby-sdk/oauth-client-credentials-default/snippet.json b/seed/ruby-sdk/oauth-client-credentials-default/snippet.json index e69de29bb2d..0614251dd46 100644 --- a/seed/ruby-sdk/oauth-client-credentials-default/snippet.json +++ b/seed/ruby-sdk/oauth-client-credentials-default/snippet.json @@ -0,0 +1,4 @@ +{ + "endpoints": [], + "types": {} +} \ No newline at end of file diff --git a/seed/ts-sdk/seed.yml b/seed/ts-sdk/seed.yml index 724cefaa734..dad9ddbc7c2 100644 --- a/seed/ts-sdk/seed.yml +++ b/seed/ts-sdk/seed.yml @@ -136,4 +136,5 @@ allowedFailures: - audiences - enum # throws b/c of undiscriminated union examples - oauth-client-credentials + - oauth-client-credentials-default - oauth-client-credentials-environment-variables From 6299f6f35f307f42628f40f14050441f1c743187 Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Mon, 13 May 2024 15:42:23 -0400 Subject: [PATCH 6/6] Update OAuth snapshots for csharp --- .../SeedOauthClientCredentialsDefault.csproj | 1 + .../.mock/definition/api.yml | 2 +- .../.mock/definition/auth.yml | 4 ++-- .../.mock/definition/api.yml | 2 +- .../.mock/definition/auth.yml | 2 +- .../Auth/AuthClient.cs | 19 ++++++++++++++++++- .../Auth/requests/GetTokenRequest.cs | 10 ++++++++++ .../Core/RawClient.cs | 19 +++++++++++-------- .../SeedOauthClientCredentialsDefault.csproj | 1 + ...SeedOauthClientCredentialsDefaultClient.cs | 4 ++-- .../.mock/definition/api.yml | 2 +- .../.mock/definition/auth.yml | 4 ++-- .../.mock/definition/api.yml | 2 +- .../.mock/definition/auth.yml | 2 +- 14 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/requests/GetTokenRequest.cs diff --git a/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj index 6b0a60236b2..49f1228d4dc 100644 --- a/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj +++ b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -7,6 +7,7 @@ + \ No newline at end of file diff --git a/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/api.yml b/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/api.yml index 02369d2d955..3869123994b 100644 --- a/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/api.yml +++ b/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials-environment-variables -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/auth.yml b/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/auth.yml index e52e3cee177..b0dc81c642a 100644 --- a/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/auth.yml +++ b/seed/csharp-model/oauth-client-credentials-environment-variables/.mock/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: @@ -28,7 +28,7 @@ service: refreshToken: path: /token method: POST - request: + request: name: RefreshTokenRequest body: properties: diff --git a/seed/csharp-model/oauth-client-credentials/.mock/definition/api.yml b/seed/csharp-model/oauth-client-credentials/.mock/definition/api.yml index 5c43f960009..3ca293f63ed 100644 --- a/seed/csharp-model/oauth-client-credentials/.mock/definition/api.yml +++ b/seed/csharp-model/oauth-client-credentials/.mock/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/seed/csharp-model/oauth-client-credentials/.mock/definition/auth.yml b/seed/csharp-model/oauth-client-credentials/.mock/definition/auth.yml index e52e3cee177..e7887dddb67 100644 --- a/seed/csharp-model/oauth-client-credentials/.mock/definition/auth.yml +++ b/seed/csharp-model/oauth-client-credentials/.mock/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs index 3066d5dad4a..019589be140 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using SeedOauthClientCredentialsDefault; namespace SeedOauthClientCredentialsDefault; @@ -11,5 +12,21 @@ public AuthClient(RawClient client) _client = client; } - public async void GetTokenAsync() { } + public async Task GetTokenAsync(GetTokenRequest request) + { + var response = await _client.MakeRequestAsync( + new RawClient.ApiRequest + { + Method = HttpMethod.Post, + Path = "/token", + Body = request + } + ); + string responseBody = await response.Raw.Content.ReadAsStringAsync(); + if (response.StatusCode >= 200 && response.StatusCode < 400) + { + return JsonSerializer.Deserialize(responseBody); + } + throw new Exception(); + } } diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/requests/GetTokenRequest.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/requests/GetTokenRequest.cs new file mode 100644 index 00000000000..fcf049dbcc2 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/requests/GetTokenRequest.cs @@ -0,0 +1,10 @@ +namespace SeedOauthClientCredentialsDefault; + +public class GetTokenRequest +{ + public string ClientId { get; init; } + + public string ClientSecret { get; init; } + + public string GrantType { get; init; } +} diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs index 98ad13e5db7..3cbf71cc9f4 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs @@ -26,13 +26,12 @@ public RawClient(Dictionary headers, ClientOptions clientOptions _headers = headers; } - public async Task MakeRequestAsync( - HttpMethod method, - string path, - ApiRequest request - ) + public async Task MakeRequestAsync(ApiRequest request) { - var httpRequest = new HttpRequestMessage(method, this.BuildUrl(path, request.Query)); + var httpRequest = new HttpRequestMessage( + request.Method, + this.BuildUrl(request.Path, request.Query) + ); if (request.ContentType != null) { request.Headers.Add("Content-Type", request.ContentType); @@ -58,7 +57,7 @@ ApiRequest request } // Send the request HttpResponseMessage response = await _clientOptions.HttpClient.SendAsync(httpRequest); - return new ApiResponse { StatusCode = (int)response.StatusCode, Body = response }; + return new ApiResponse { StatusCode = (int)response.StatusCode, Raw = response }; } ///

@@ -66,6 +65,10 @@ ApiRequest request /// public class ApiRequest { + public HttpMethod Method; + + public string Path; + public string? ContentType = null; public object? Body { get; init; } = null; @@ -84,7 +87,7 @@ public class ApiResponse { public int StatusCode; - public HttpResponseMessage Body; + public HttpResponseMessage Raw; } private Dictionary GetHeaders(ApiRequest request) diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj index 6b0a60236b2..49f1228d4dc 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -7,6 +7,7 @@ + \ No newline at end of file diff --git a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs index fcc6d667436..a2ca79eb74f 100644 --- a/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefaultClient.cs @@ -6,10 +6,10 @@ public partial class SeedOauthClientCredentialsDefaultClient { private RawClient _client; - public SeedOauthClientCredentialsDefaultClient(string token, ClientOptions clientOptions) + public SeedOauthClientCredentialsDefaultClient(string token, ClientOptions clientOptions = null) { _client = new RawClient( - new Dictionary { { "X-Fern-Language", "C#" }, }, + new Dictionary() { { "X-Fern-Language", "C#" }, }, clientOptions ?? new ClientOptions() ); Auth = new AuthClient(_client); diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/api.yml b/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/api.yml index 02369d2d955..3869123994b 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/api.yml +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials-environment-variables -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/auth.yml b/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/auth.yml index e52e3cee177..b0dc81c642a 100644 --- a/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/auth.yml +++ b/seed/csharp-sdk/oauth-client-credentials-environment-variables/.mock/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: @@ -28,7 +28,7 @@ service: refreshToken: path: /token method: POST - request: + request: name: RefreshTokenRequest body: properties: diff --git a/seed/csharp-sdk/oauth-client-credentials/.mock/definition/api.yml b/seed/csharp-sdk/oauth-client-credentials/.mock/definition/api.yml index 5c43f960009..3ca293f63ed 100644 --- a/seed/csharp-sdk/oauth-client-credentials/.mock/definition/api.yml +++ b/seed/csharp-sdk/oauth-client-credentials/.mock/definition/api.yml @@ -1,5 +1,5 @@ name: oauth-client-credentials -imports: +imports: auth: auth.yml auth: OAuthScheme diff --git a/seed/csharp-sdk/oauth-client-credentials/.mock/definition/auth.yml b/seed/csharp-sdk/oauth-client-credentials/.mock/definition/auth.yml index e52e3cee177..e7887dddb67 100644 --- a/seed/csharp-sdk/oauth-client-credentials/.mock/definition/auth.yml +++ b/seed/csharp-sdk/oauth-client-credentials/.mock/definition/auth.yml @@ -14,7 +14,7 @@ service: getTokenWithClientCredentials: path: /token method: POST - request: + request: name: GetTokenRequest body: properties: