Skip to content

Commit

Permalink
feat: Add endpoint.workspaceScope (#139)
Browse files Browse the repository at this point in the history
Co-authored-by: Seam Bot <seambot@getseam.com>
  • Loading branch information
andrii-balitskyi and seambot authored Dec 17, 2024
1 parent ee1f62a commit fcf61bd
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 8 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions src/lib/blueprint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
createProperties,
getPreferredMethod,
getSemanticMethod,
getWorkspaceScope,
type Method,
type OpenapiAuthMethod,
} from 'lib/blueprint.js'
import type { OpenapiOperation, OpenapiSchema } from 'lib/openapi.js'

Expand Down Expand Up @@ -343,3 +345,49 @@ test('getPreferredMethod: delete and post', (t) => {
'Preferred method should be POST when both DELETE and POST are available',
)
})

test('getWorkspaceScope: no auth methods', (t) => {
const authMethods: OpenapiAuthMethod[] = []
t.is(
getWorkspaceScope(authMethods),
'none',
'Workspace scope should be "none" when no auth methods are present',
)
})

test('getWorkspaceScope: only unscoped auth methods', (t) => {
const authMethods: OpenapiAuthMethod[] = [
'pat_without_workspace',
'console_session_token_without_workspace',
]
t.is(
getWorkspaceScope(authMethods),
'none',
'Workspace scope should be "none" when only unscoped auth methods are present',
)
})

test('getWorkspaceScope: only scoped auth methods', (t) => {
const authMethods: OpenapiAuthMethod[] = [
'api_key',
'client_session',
'pat_with_workspace',
]
t.is(
getWorkspaceScope(authMethods),
'required',
'Workspace scope should be "required" when only scoped auth methods are present',
)
})

test('getWorkspaceScope: both scoped and unscoped auth methods', (t) => {
const authMethods: OpenapiAuthMethod[] = [
'pat_with_workspace',
'pat_without_workspace',
]
t.is(
getWorkspaceScope(authMethods),
'optional',
'Workspace scope should be "optional" when both scoped and unscoped auth methods are present',
)
})
57 changes: 50 additions & 7 deletions src/lib/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export interface Endpoint {
response: Response
codeSamples: CodeSample[]
authMethods: SeamAuthMethod[]
workspaceScope: SeamWorkspaceScope
}

export type SeamAuthMethod =
Expand All @@ -82,6 +83,8 @@ export type SeamAuthMethod =
| 'client_session_token'
| 'publishable_key'

export type SeamWorkspaceScope = 'none' | 'optional' | 'required'

interface BaseParameter {
name: string
description: string
Expand Down Expand Up @@ -503,12 +506,16 @@ const createEndpointFromOperation = async (
const request = createRequest(methods, operation, path)
const response = createResponse(operation, path)

const authMethods = parsedOperation.security
.map((securitySchema) => {
const operationAuthMethods = parsedOperation.security.map(
(securitySchema) => {
const [authMethod = ''] = Object.keys(securitySchema)
return mapOpenapiToSeamAuthMethod(authMethod)
})
return authMethod as OpenapiAuthMethod
},
)
const endpointAuthMethods = operationAuthMethods
.map(mapOpenapiToSeamAuthMethod)
.filter((authMethod): authMethod is SeamAuthMethod => authMethod != null)
const workspaceScope = getWorkspaceScope(operationAuthMethods)

const endpoint: Omit<Endpoint, 'codeSamples'> = {
title,
Expand All @@ -523,7 +530,8 @@ const createEndpointFromOperation = async (
draftMessage,
response,
request,
authMethods,
authMethods: endpointAuthMethods,
workspaceScope,
}

return {
Expand All @@ -542,7 +550,41 @@ const createEndpointFromOperation = async (
}
}

type OpenapiAuthMethod = z.infer<typeof AuthMethodSchema>
export type OpenapiAuthMethod = z.infer<typeof AuthMethodSchema>

export const getWorkspaceScope = (
authMethods: OpenapiAuthMethod[],
): SeamWorkspaceScope => {
const hasWorkspaceUnscoped = authMethods.some((method) =>
method.endsWith('_without_workspace'),
)

const workspaceScopedAuthMethods: OpenapiAuthMethod[] = [
'api_key',
'client_session',
'console_session_token_with_workspace',
'pat_with_workspace',
'publishable_key',
]
const hasWorkspaceScoped = authMethods.some((method) =>
workspaceScopedAuthMethods.includes(method),
)

const hasNoAuthMethods = !hasWorkspaceUnscoped && !hasWorkspaceScoped
if (hasNoAuthMethods) return 'none'

const hasOnlyUnscopedAuth = hasWorkspaceUnscoped && !hasWorkspaceScoped
if (hasOnlyUnscopedAuth) return 'none'

const hasBothScopedAndUnscoped = hasWorkspaceUnscoped && hasWorkspaceScoped
if (hasBothScopedAndUnscoped) return 'optional'

const hasOnlyScopedAuth = !hasWorkspaceUnscoped && hasWorkspaceScoped
if (hasOnlyScopedAuth) return 'required'

return 'none'
}

type KnownOpenapiAuthMethod = Exclude<OpenapiAuthMethod, 'unknown'>

const mapOpenapiToSeamAuthMethod = (
Expand All @@ -552,7 +594,8 @@ const mapOpenapiToSeamAuthMethod = (
api_key: 'api_key',
pat_with_workspace: 'personal_access_token',
pat_without_workspace: 'personal_access_token',
console_session: 'console_session_token',
console_session_token_with_workspace: 'console_session_token',
console_session_token_without_workspace: 'console_session_token',
client_session: 'client_session_token',
publishable_key: 'publishable_key',
} as const
Expand Down
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export {
type Response,
type Route,
type SeamAuthMethod,
type SeamWorkspaceScope,
type TypesModule,
type TypesModuleInput,
TypesModuleSchema,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/openapi-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export const AuthMethodSchema = z
.enum([
'api_key',
'client_session',
'console_session',
'console_session_token_with_workspace',
'console_session_token_without_workspace',
'pat_with_workspace',
'pat_without_workspace',
'publishable_key',
Expand Down
10 changes: 10 additions & 0 deletions test/snapshots/blueprint.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Get a foo',
undocumentedMessage: '',
workspaceScope: 'required',
},
{
authMethods: [
Expand Down Expand Up @@ -521,6 +522,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'List foos',
undocumentedMessage: '',
workspaceScope: 'required',
},
],
isDeprecated: false,
Expand Down Expand Up @@ -645,6 +647,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'List planes',
undocumentedMessage: '',
workspaceScope: 'none',
},
],
isDeprecated: false,
Expand Down Expand Up @@ -764,6 +767,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Deprecated and undocumented endpoint',
undocumentedMessage: 'true',
workspaceScope: 'none',
},
],
isDeprecated: true,
Expand Down Expand Up @@ -883,6 +887,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Draft endpoint',
undocumentedMessage: '',
workspaceScope: 'none',
},
],
isDeprecated: false,
Expand Down Expand Up @@ -1296,6 +1301,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Get a foo',
undocumentedMessage: '',
workspaceScope: 'required',
},
{
authMethods: [
Expand Down Expand Up @@ -1446,6 +1452,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'List foos',
undocumentedMessage: '',
workspaceScope: 'required',
},
],
isDeprecated: false,
Expand Down Expand Up @@ -1586,6 +1593,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'List planes',
undocumentedMessage: '',
workspaceScope: 'none',
},
],
isDeprecated: false,
Expand Down Expand Up @@ -1721,6 +1729,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Deprecated and undocumented endpoint',
undocumentedMessage: 'true',
workspaceScope: 'none',
},
],
isDeprecated: true,
Expand Down Expand Up @@ -1856,6 +1865,7 @@ Generated by [AVA](https://avajs.dev).
},
title: 'Draft endpoint',
undocumentedMessage: '',
workspaceScope: 'none',
},
],
isDeprecated: false,
Expand Down
Binary file modified test/snapshots/blueprint.test.ts.snap
Binary file not shown.
Loading

0 comments on commit fcf61bd

Please sign in to comment.