diff --git a/.pnp.cjs b/.pnp.cjs index 26b49408e8..fde03dc585 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -7617,6 +7617,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 0000000000..f3316970d3 --- /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 92bba3daa7..63f59343d4 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 db14f9fb01..6d9305f574 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 bcccc09956..285bd3cbaa 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 582ecd8f59..d13294f290 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 e52e3cee17..e7887dddb6 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 0000000000..d18ad5b19c --- /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 0000000000..ce6074f746 --- /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 0000000000..a359229fc5 --- /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 0000000000..de1b6e4525 --- /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 0000000000..7dd0fe0c04 --- /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 0000000000..d8d54d4853 --- /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 0000000000..a74aef6a41 --- /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 0000000000..f71f44ef31 --- /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 0000000000..a74aef6a41 --- /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 0000000000..34ebf18d52 --- /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 ed7324af30..83a416712b 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 e52e3cee17..b0dc81c642 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 386a8530d0..b0d42d3210 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,38 +4,113 @@ 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.", + 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.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + } + ]; + expect(() => + validateOAuthRuleViolations({ + expected: expectedViolations, + actual: violations + }) + ).not.toThrow(); + }); + + 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.", 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.", nodePath: ["service", "endpoints", "getTokenWithClientCredentials"], relativeFilepath: RelativeFilePath.of("auth.yml"), severity: "error" @@ -69,6 +144,70 @@ describe("valid-oauth", () => { severity: "error" } ]; - expect(violations).toEqual(expectedViolations); + expect(() => + validateOAuthRuleViolations({ + expected: expectedViolations, + actual: violations + }) + ).not.toThrow(); + }); + + 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'.", + 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'.", + 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.", + nodePath: ["service", "endpoints", "getToken"], + relativeFilepath: RelativeFilePath.of("auth.yml"), + severity: "error" + } + ]; + 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)); +} 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 98b255084c..3ebfef3aad 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 398aca0e48..8f81502f0d 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 ddd49c1d83..6d98bdc08a 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 37a2fe7d6f..db3095fdbb 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 3398a81238..871170a0c8 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 a5cdb66944..23fe7061c5 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 6df3e7d5e5..d627f3c664 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 8c68b71425..2871d390e3 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 6d72a487ba..0000000000 --- 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 0000000000..1fd12bfad8 --- /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 0000000000..f5031f2974 --- /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 3495aa135a..08ad35155d 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 2053655874..e3371adde4 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 0a03d6c928..0000000000 --- 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 0000000000..7555db9129 --- /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 3c06ef0b76..aecd119891 100644 --- a/packages/cli/yaml/yaml-schema/src/schemas/index.ts +++ b/packages/cli/yaml/yaml-schema/src/schemas/index.ts @@ -44,9 +44,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/seed/csharp-model/oauth-client-credentials-default/.gitignore b/seed/csharp-model/oauth-client-credentials-default/.gitignore new file mode 100644 index 0000000000..9965de2966 --- /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 0000000000..be1f2437d4 --- /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 0000000000..b9c7c82a6f --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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/packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/generators.yml b/seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml similarity index 100% rename from packages/cli/yaml/validator/src/rules/valid-oauth/__test__/fixtures/valid/generators.yml rename to seed/csharp-model/oauth-client-credentials-default/.mock/generators.yml 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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..17cab683ff --- /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 0000000000..c81aaefcc7 --- /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 0000000000..49f1228d4d --- /dev/null +++ b/seed/csharp-model/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + + + + + + + + \ 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 02369d2d95..3869123994 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 e52e3cee17..b0dc81c642 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 5c43f96000..3ca293f63e 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 e52e3cee17..e7887dddb6 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/.gitignore b/seed/csharp-sdk/oauth-client-credentials-default/.gitignore new file mode 100644 index 0000000000..9965de2966 --- /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 0000000000..27b20c665d --- /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 0000000000..b9c7c82a6f --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..17cab683ff --- /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 0000000000..5121aaf011 --- /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 0000000000..019589be14 --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/AuthClient.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using SeedOauthClientCredentialsDefault; + +namespace SeedOauthClientCredentialsDefault; + +public class AuthClient +{ + private RawClient _client; + + public AuthClient(RawClient client) + { + _client = client; + } + + 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/Types/TokenResponse.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/Types/TokenResponse.cs new file mode 100644 index 0000000000..c81aaefcc7 --- /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/Auth/requests/GetTokenRequest.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Auth/requests/GetTokenRequest.cs new file mode 100644 index 0000000000..fcf049dbcc --- /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/ClientOptions.cs b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/ClientOptions.cs new file mode 100644 index 0000000000..d9d21a4e24 --- /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 0000000000..3cbf71cc9f --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/Core/RawClient.cs @@ -0,0 +1,121 @@ +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(ApiRequest request) + { + var httpRequest = new HttpRequestMessage( + request.Method, + this.BuildUrl(request.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, Raw = response }; + } + + /// + /// The request object to be sent to the API. + /// + public class ApiRequest + { + public HttpMethod Method; + + public string Path; + + 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 Raw; + } + + 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 0000000000..49f1228d4d --- /dev/null +++ b/seed/csharp-sdk/oauth-client-credentials-default/src/SeedOauthClientCredentialsDefault/SeedOauthClientCredentialsDefault.csproj @@ -0,0 +1,13 @@ + + + + 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 0000000000..a2ca79eb74 --- /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 = null) + { + _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/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 02369d2d95..3869123994 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 e52e3cee17..b0dc81c642 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 5c43f96000..3ca293f63e 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 e52e3cee17..e7887dddb6 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: 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 0000000000..cd6b9b5171 --- /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 0000000000..5b243c4c20 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..72dd3d705a --- /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 0000000000..f93afe085b --- /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 0000000000..da7c8dc49c --- /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 0000000000..7c9864a944 --- /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 0000000000..297d6e06f5 --- /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 0000000000..bdf0386248 --- /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 0000000000..fe5ac5419c --- /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 0000000000..32d532e5ef --- /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 0000000000..952b5f2a8a --- /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 0000000000..4228e2fe05 --- /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 0000000000..e69ee6d9c5 --- /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 0000000000..023342b668 --- /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 0000000000..4275ccb6bd --- /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 0000000000..2186393473 --- /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 0000000000..49aef9819c --- /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 0000000000..28bf519c1d --- /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 0000000000..96070ef443 --- /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 0000000000..9aa34aae00 --- /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 0000000000..2ab0052fce --- /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 0000000000..643fd071bc --- /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 0000000000..bab014441e --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..d4c0a5dcd9 --- /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 0000000000..be1f2437d4 --- /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 0000000000..ee9faca127 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..cc23b9409b --- /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 0000000000..000cf44864 --- /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 0000000000..d009ab30c9 --- /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 0000000000..a83d69daa3 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..d4c0a5dcd9 --- /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 0000000000..be1f2437d4 --- /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 0000000000..ee9faca127 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..2ede3ee834 --- /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 0000000000..000cf44864 --- /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 0000000000..d009ab30c9 --- /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 0000000000..a83d69daa3 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..d4c0a5dcd9 --- /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 0000000000..be1f2437d4 --- /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 0000000000..ee9faca127 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..0991af86b5 --- /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 0000000000..29714ed966 --- /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 0000000000..730f6d70ae --- /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 0000000000..827e6bd448 --- /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 0000000000..3e28f90853 --- /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 0000000000..f476f9ee38 --- /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 0000000000..3febdc7974 --- /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 0000000000..aad030a370 --- /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 0000000000..bd6615e12a --- /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 0000000000..ea24916b78 --- /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 0000000000..000cf44864 --- /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 0000000000..d009ab30c9 --- /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 0000000000..651be67c60 --- /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 0000000000..b3766d4366 --- /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 0000000000..90e0a7fdd5 --- /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 0000000000..6ef1f26a52 --- /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 0000000000..e69de29bb2 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 0000000000..1c8ce3363e --- /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 0000000000..8598a73092 --- /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 0000000000..d4199abc2c --- /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 0000000000..27b20c665d --- /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 0000000000..59adde187d --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..052f398146 --- /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 0000000000..d64cd49177 Binary files /dev/null and b/seed/java-model/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar differ 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 0000000000..1af9e0930b --- /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 0000000000..1aa94a4269 --- /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 0000000000..6689b85bee --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..1299f55e57 --- /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 0000000000..a91b9c0f6c --- /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 0000000000..e775525c80 --- /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 0000000000..8598a73092 --- /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 0000000000..d4199abc2c --- /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 0000000000..27b20c665d --- /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 0000000000..59adde187d --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..6601fd8e9f --- /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 0000000000..e6441136f3 Binary files /dev/null and b/seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.jar differ diff --git a/seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties b/seed/java-sdk/oauth-client-credentials-default/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b82aa23a4f --- /dev/null +++ b/seed/java-sdk/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.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/seed/java-sdk/oauth-client-credentials-default/gradlew b/seed/java-sdk/oauth-client-credentials-default/gradlew new file mode 100755 index 0000000000..1aa94a4269 --- /dev/null +++ b/seed/java-sdk/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-sdk/oauth-client-credentials-default/gradlew.bat b/seed/java-sdk/oauth-client-credentials-default/gradlew.bat new file mode 100644 index 0000000000..7101f8e467 --- /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 0000000000..4ee8f227b7 --- /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 0000000000..356de5a3f3 --- /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 0000000000..aed36fec10 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..313b7d4e82 --- /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 0000000000..b142daeae6 --- /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 0000000000..c262c4e5c2 --- /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 0000000000..715f29a21f --- /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 0000000000..1299f55e57 --- /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 0000000000..8c1944c5e9 --- /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 0000000000..747d3d47ac --- /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 0000000000..a91b9c0f6c --- /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 0000000000..e50bbe202a --- /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 0000000000..c36a09abd5 --- /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 0000000000..c0ca320734 --- /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 0000000000..43ae7291c8 --- /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 0000000000..1ecdf428d1 --- /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 0000000000..8285924d1c --- /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 0000000000..2e4190e22f --- /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 0000000000..02668e48ad --- /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 0000000000..cd6b9b5171 --- /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 0000000000..59adde187d --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..27289cf9b2 --- /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 0000000000..58a05842c2 --- /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 0000000000..3d3174aec0 --- /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 0000000000..e02822614a --- /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 0000000000..f0096d1095 --- /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 0000000000..169bd910b8 --- /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 0000000000..5108882b0a --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..cd6b9b5171 --- /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 0000000000..c76223835a --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..3960b90e8d --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..cd6b9b5171 --- /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 0000000000..c76223835a --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..1331399373 --- /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 0000000000..42cb863501 --- /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 0000000000..0bdc0b93fb --- /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 0000000000..5b243c4c20 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..e69de29bb2 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 0000000000..cb78a51611 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..c1750dcca6 --- /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 0000000000..b677880f4f --- /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 0000000000..7c9864a944 --- /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 0000000000..952b5f2a8a --- /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 0000000000..e69de29bb2 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 0000000000..67b9ca3d89 --- /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 0000000000..2ab0052fce --- /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 0000000000..299831a06d --- /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 0000000000..60a58e64c2 --- /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 0000000000..1331399373 --- /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 0000000000..42cb863501 --- /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 0000000000..0bdc0b93fb --- /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 0000000000..5e28ba4c46 --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..e69de29bb2 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 0000000000..605c38f5fe --- /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 0000000000..365f502205 --- /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 0000000000..9d67e38492 --- /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 0000000000..4a009e5fcb --- /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 0000000000..3d9382fea5 --- /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 0000000000..f19e7a35d7 --- /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 0000000000..2ab0052fce --- /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 0000000000..1933aa1d22 --- /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 0000000000..594cad7915 --- /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 0000000000..78a7f80fb3 --- /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 0000000000..2e9fc5431c --- /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 0000000000..abaefdd0ba --- /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 0000000000..7c9864a944 --- /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 0000000000..cb0d40bbbf --- /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 0000000000..4e6877df25 --- /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 0000000000..7f48273263 --- /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 0000000000..abde7aae67 --- /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 0000000000..952b5f2a8a --- /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 0000000000..2da30f7133 --- /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 0000000000..cd6f27a7e9 --- /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 0000000000..e69de29bb2 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 0000000000..42124c75b9 --- /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 0000000000..60a58e64c2 --- /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/python-sdk/seed.yml b/seed/python-sdk/seed.yml index 73c8551619..35c1ecff38 100644 --- a/seed/python-sdk/seed.yml +++ b/seed/python-sdk/seed.yml @@ -107,3 +107,4 @@ allowedFailures: - extra-properties - trace - circular-references-advanced + - oauth-client-credentials-default 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 0000000000..cd6b9b5171 --- /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 0000000000..59adde187d --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..c1d2344d6e --- /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 0000000000..49bd9cd017 --- /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 0000000000..2bdbce0cf2 --- /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 0000000000..65720bd53a --- /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 0000000000..a029ac5601 --- /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 0000000000..0545f83ec9 --- /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 0000000000..5b08af4995 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..3cf1d5fc2d --- /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 0000000000..e373f4a798 --- /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 0000000000..4bfa01fe7a --- /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 0000000000..a97c182a2e --- /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 0000000000..e869033bc4 --- /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 0000000000..59adde187d --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..c1d2344d6e --- /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 0000000000..49bd9cd017 --- /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 0000000000..e69de29bb2 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 0000000000..2bdbce0cf2 --- /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 0000000000..34e2b14125 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/fern_oauth_client_credentials_default.gemspec @@ -0,0 +1,25 @@ +# 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"] + 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 new file mode 100644 index 0000000000..6b815a96a6 --- /dev/null +++ b/seed/ruby-sdk/oauth-client-credentials-default/lib/fern_oauth_client_credentials_default.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +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 0000000000..f086e9433b --- /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/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 0000000000..0545f83ec9 --- /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 0000000000..898f11b2c7 --- /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/lib/requests.rb b/seed/ruby-sdk/oauth-client-credentials-default/lib/requests.rb new file mode 100644 index 0000000000..98eeb45a5e --- /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 0000000000..7fb344e044 --- /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-templates.json b/seed/ruby-sdk/oauth-client-credentials-default/snippet-templates.json new file mode 100644 index 0000000000..e69de29bb2 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 0000000000..0614251dd4 --- /dev/null +++ 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/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 0000000000..ff99894151 --- /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 0000000000..6b7dd541aa --- /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 0000000000..a4518867f0 --- /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 0000000000..ed3c996cde --- /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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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 0000000000..4c8e54ac31 --- /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 0000000000..0967ef424b --- /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 0000000000..3e5335fe42 --- /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 0000000000..fcc81debec --- /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 0000000000..c86ec5c8ea --- /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 0000000000..415726b7fe --- /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 0000000000..e108013546 --- /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 0000000000..c890bee607 --- /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 0000000000..f25212b570 --- /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 0000000000..6848a730c9 --- /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 0000000000..f6dde5f4e8 --- /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 0000000000..3ae53c06d3 --- /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 0000000000..870f373ba8 --- /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 0000000000..b70f24b045 --- /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 0000000000..187b29040f --- /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 0000000000..c1e24d69de --- /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 0000000000..fe6faed93e --- /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 0000000000..050cd2c4ef --- /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 0000000000..77420fb031 --- /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 0000000000..a665472d22 --- /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 0000000000..e48c016667 --- /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 0000000000..25f4bcc173 --- /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 0000000000..b333321b50 --- /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 0000000000..a83d22cd48 --- /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 0000000000..d2bf08fc6c --- /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 0000000000..3939b76b48 --- /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 0000000000..270ea170c8 --- /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 0000000000..c342e72cf9 --- /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 0000000000..75b3698729 --- /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 0000000000..e3f4388db2 --- /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 0000000000..6427678b22 --- /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 0000000000..a0951f48ef --- /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 0000000000..d245c4b193 --- /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 0000000000..17cff4f86d --- /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 0000000000..fcaeb04255 --- /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 0000000000..fad6056212 --- /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 0000000000..788f9416bf --- /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 0000000000..c268945693 --- /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 0000000000..949f1f2a63 --- /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 0000000000..4d5249571f --- /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 0000000000..82e25c5c2a --- /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 0000000000..ac1cd22ade --- /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 0000000000..eb82cc7f65 --- /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 0000000000..2b89ca0e7a --- /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 0000000000..d056eb45cf --- /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 0000000000..0c0d379d80 --- /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 0000000000..aa04e051df --- /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 0000000000..4160f0a261 --- /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 0000000000..f3310e8bda --- /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 0000000000..3113bcba30 --- /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 0000000000..75b71cb356 --- /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 0000000000..43e7108a06 --- /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 0000000000..771dc6a7ef --- /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 0000000000..55065bc894 --- /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 0000000000..85fc008a2d --- /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 0000000000..6f82c868b2 --- /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 0000000000..ed659beb62 --- /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 0000000000..5429d8b43e --- /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 0000000000..9cd354b341 --- /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 0000000000..4111d703cd --- /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 0000000000..de107cf5ee --- /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 0000000000..e122952137 --- /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 0000000000..2c25a3455b --- /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 0000000000..438012df41 --- /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 0000000000..db82a722c3 --- /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 0000000000..0186709828 --- /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 0000000000..99c02c32bd --- /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 0000000000..f58d6f3d35 --- /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 0000000000..e7d4a64405 --- /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 0000000000..1b6de2104c --- /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 0000000000..21dddb213e --- /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 0000000000..31a60ca7ba --- /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 0000000000..3e5335fe42 --- /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 0000000000..fcc81debec --- /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 0000000000..415726b7fe --- /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 0000000000..05bef652f2 --- /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 0000000000..c890bee607 --- /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 0000000000..47c972b8e2 --- /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 0000000000..6848a730c9 --- /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 0000000000..f6dde5f4e8 --- /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 0000000000..e69de29bb2 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 0000000000..e69de29bb2 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 0000000000..95a9fda95a --- /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 0000000000..ed3c996cde --- /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 diff --git a/seed/ts-sdk/seed.yml b/seed/ts-sdk/seed.yml index 89af33395e..6fe8ee352c 100644 --- a/seed/ts-sdk/seed.yml +++ b/seed/ts-sdk/seed.yml @@ -137,4 +137,5 @@ allowedFailures: - audiences - enum # throws b/c of undiscriminated union examples - oauth-client-credentials + - oauth-client-credentials-default - oauth-client-credentials-environment-variables 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 0000000000..e94a5d4e99 --- /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 0000000000..ca7f401756 --- /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/test-definitions/fern/apis/oauth-client-credentials-default/generators.yml b/test-definitions/fern/apis/oauth-client-credentials-default/generators.yml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/test-definitions/fern/apis/oauth-client-credentials-default/generators.yml @@ -0,0 +1 @@ +{} 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 02369d2d95..3869123994 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 e52e3cee17..b0dc81c642 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 5c43f96000..3ca293f63e 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 e52e3cee17..e7887dddb6 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 be59e344b2..795d8b1a37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4523,6 +4523,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