diff --git a/apps/backend/package.json b/apps/backend/package.json index 6d458a8ca..d2ec7add2 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -63,6 +63,7 @@ "openid-client": "^5.6.4", "oslo": "^1.2.1", "posthog-node": "^4.1.0", + "prettier": "^3.4.2", "react": "^19.0.0", "react-dom": "^19.0.0", "semver": "^7.6.3", diff --git a/apps/backend/scripts/generate-docs.ts b/apps/backend/scripts/generate-docs.ts index a38a7b1c2..feeeca843 100644 --- a/apps/backend/scripts/generate-docs.ts +++ b/apps/backend/scripts/generate-docs.ts @@ -1,36 +1,15 @@ +import { listEndpoints } from '@/lib/glob'; import { parseOpenAPI, parseWebhookOpenAPI } from '@/lib/openapi'; -import { isSmartRouteHandler } from '@/route-handlers/smart-route-handler'; import { webhookEvents } from '@stackframe/stack-shared/dist/interface/webhooks'; -import { HTTP_METHODS } from '@stackframe/stack-shared/dist/utils/http'; -import { typedKeys } from '@stackframe/stack-shared/dist/utils/objects'; import fs from 'fs'; -import { glob } from 'glob'; -import path from 'path'; import yaml from 'yaml'; async function main() { console.log("Started docs schema generator"); for (const audience of ['client', 'server', 'admin'] as const) { - const filePathPrefix = path.resolve(process.platform === "win32" ? "apps/src/app/api/v1" : "src/app/api/v1"); - const importPathPrefix = "@/app/api/v1"; - const filePaths = [...await glob(filePathPrefix + "/**/route.{js,jsx,ts,tsx}")]; const openAPISchema = yaml.stringify(parseOpenAPI({ - endpoints: new Map(await Promise.all(filePaths.map(async (filePath) => { - if (!filePath.startsWith(filePathPrefix)) { - throw new Error(`Invalid file path: ${filePath}`); - } - const suffix = filePath.slice(filePathPrefix.length); - const midfix = suffix.slice(0, suffix.lastIndexOf("/route.")); - const importPath = `${importPathPrefix}${suffix}`; - const urlPath = midfix.replaceAll("[", "{").replaceAll("]", "}"); - const myModule = require(importPath); - const handlersByMethod = new Map( - typedKeys(HTTP_METHODS).map(method => [method, myModule[method]] as const) - .filter(([_, handler]) => isSmartRouteHandler(handler)) - ); - return [urlPath, handlersByMethod] as const; - }))), + endpoints: await listEndpoints("api/v1", true, true), audience, })); fs.writeFileSync(`../../docs/fern/openapi/${audience}.yaml`, openAPISchema); diff --git a/apps/backend/scripts/generate-schema.ts b/apps/backend/scripts/generate-schema.ts new file mode 100644 index 000000000..9947863f9 --- /dev/null +++ b/apps/backend/scripts/generate-schema.ts @@ -0,0 +1,216 @@ +import { listEndpoints } from '@/lib/glob'; +import { isSmartRouteHandler } from '@/route-handlers/smart-route-handler'; +import fs from 'fs'; +import prettier from 'prettier'; +import * as yup from 'yup'; + +function convertUrlToJSVariable(url: string, method: string) { + return 'i' + url.replaceAll('[', '') + .replaceAll(']', '') + .replaceAll('.', '') + .replaceAll('/', '_') + .replaceAll('-', '_') + .replace(/_[a-z]/g, match => match[1].toUpperCase()) + .replace(/^[a-z]/, match => match.toUpperCase()) + + method.slice(0, 1).toUpperCase() + method.slice(1).toLowerCase(); +} + +async function main() { + console.log("Started docs schema generator"); + + const endpoints = await listEndpoints("api/v1", false); + + // ========== generate schema.ts ========== + let schemaContent = 'import { yupObject, yupArray, yupString, yupNumber, yupBoolean, yupMixed } from "@stackframe/stack-shared/dist/schema-fields";\n\n'; + schemaContent += 'export const endpointSchema = {'; + + endpoints.forEach((handlersByMethod, url) => { + let methodContent = '{'; + + handlersByMethod.forEach((handler, method) => { + if (!isSmartRouteHandler(handler)) { + // TODO: handle non-smart route handlers + console.warn(`Skipping non-smart route handler: ${url} ${method}`); + return; + } + + const audiences = new Map(); + for (const overload of handler.overloads.values()) { + for (const audience of ['client', 'server', 'admin'] as const) { + const schemaAudience = (overload.request.describe() as any).fields.auth?.fields?.type; + if (!schemaAudience) continue; + if ("oneOf" in schemaAudience && schemaAudience.oneOf.length > 0 && schemaAudience.oneOf.includes(audience)) { + audiences.set(audience, overload); + } + } + } + + if (handler.overloads.size !== 1 && audiences.size !== handler.overloads.size) { + throw new Error(`Expected ${handler.overloads.size} audiences, got ${audiences.size}. Multiple audiences other than client, server, and admin is currently not supported. You might need to manually fix this.`); + } + + let endpointContent; + if (audiences.size === 0) { + endpointContent = '{default: ' + endpointSchemaToTypeString( + handler.overloads.values().next().value.request.describe(), + handler.overloads.values().next().value.response.describe() + ) + '}'; + } else { + endpointContent = '{' + Array.from(audiences.entries()).map(([audience, overload]) => { + return `${audience}: ${endpointSchemaToTypeString(overload.request.describe(), overload.response.describe())}`; + }).join(',') + '}'; + } + + methodContent += `${method}: ${endpointContent},`; + }); + + methodContent += '}'; + schemaContent += `"${url || '/'}": ${methodContent},`; + }); + + schemaContent += '}'; + + // ========== generate imports.ts ========== + let importHeaders = ''; + let importBody = 'export const endpoints = {'; + + endpoints.forEach((handlersByMethod, url) => { + let methodBody = ''; + for (const method of handlersByMethod.keys()) { + importHeaders += `import { ${method} as ${convertUrlToJSVariable(url, method)} } from "../../api/v1${url}/route";\n`; + methodBody += `"${method}": ${convertUrlToJSVariable(url, method)},`; + } + importBody += `"${url || '/'}": {${methodBody}},\n`; + }); + + importBody += '}'; + // ======================================== + + const prettierConfig = { + parser: "typescript", + semi: true, + singleQuote: true, + trailingComma: "all", + } as const; + + fs.writeFileSync('src/app/api/v2/schema.ts', await prettier.format(schemaContent, prettierConfig)); + fs.writeFileSync('src/app/api/v2/imports.ts', await prettier.format(importHeaders + '\n' + importBody, prettierConfig)); +} + +function endpointSchemaToTypeString(reqSchema: yup.SchemaFieldDescription, resSchema: yup.SchemaFieldDescription): string { + if (reqSchema.type !== 'object') { + throw new Error(`Unsupported schema type: ${reqSchema.type}`); + } + let inputFields = "{"; + for (const key of ['body', 'query', 'params']) { + const field = Object.entries((reqSchema as any).fields).find(([k]) => k === key); + if (field && Object.keys((field[1] as any).fields || {}).length > 0) { + inputFields += `${key}: ${schemaToTypeString(field[1] as any)},`; + } else { + inputFields += `${key}: yupObject({}),`; + } + } + inputFields += "}"; + + let outputFields = "{"; + const rawOutputFields = (resSchema as any).fields; + if (rawOutputFields) { + for (const key of ['statusCode', 'bodyType', 'headers', 'body']) { + const field = Object.entries(rawOutputFields).find(([k]) => k === key); + if (field) { + if (key === 'statusCode') { + outputFields += `statusCode: [${(field[1] as any).oneOf.join(',')}],`; + } else if (key === 'bodyType') { + const bodyType = (field[1] as any).oneOf; + if (bodyType.length !== 1) { + throw new Error(`Unsupported body type: ${bodyType}`); + } + outputFields += `bodyType: "${bodyType[0]}",`; + } else { + outputFields += `${key}: ${schemaToTypeString(field[1] as any)},`; + } + } + } + } + outputFields += "}"; + + return `{ + input: ${inputFields}, + output: ${outputFields}, + }`; +} + +function schemaToTypeString(schema: yup.SchemaFieldDescription): string { + let result; + switch (schema.type) { + case 'object': { + result = `yupObject({${Object.entries((schema as any).fields).map(([key, value]): any => `"${key}": ${schemaToTypeString(value as any)}`).join(',')}})`; + break; + } + case 'array': { + result = `yupArray(${schemaToTypeString((schema as any).innerType)})`; + break; + } + case 'tuple': { + result = `yupTuple([${(schema as any).innerType.map((value: any) => schemaToTypeString(value)).join(',')}])`; + break; + } + case 'mixed': { + result = 'yupMixed()'; + break; + } + case 'string': { + result = 'yupString()'; + break; + } + case 'number': { + result = 'yupNumber()'; + break; + } + case 'boolean': { + result = 'yupBoolean()'; + break; + } + default: { + throw new Error(`Unsupported schema type: ${schema.type}`); + } + } + + const optional = (schema as any).optional; + const nullable = (schema as any).nullable; + + if (!optional && !nullable) { + result += '.defined()'; + } + + if (optional) { + result += '.optional()'; + } + + if (nullable) { + result += '.nullable()'; + } + + if ((schema as any).oneOf && (schema as any).oneOf.length > 0 && (schema as any).oneOf.every((value: any) => value !== undefined)) { + result += `.oneOf([${(schema as any).oneOf + .map((value: any) => { + if (typeof value === 'string') { + return `"${value}"`; + } else if (typeof value === 'boolean') { + return value ? 'true' : 'false'; + } else if (typeof value === 'number') { + return value.toString(); + } else { + throw new Error(`Unsupported oneOf value: ${value}`); + } + }) + .join(',')}])`; + } + + return result; +} + +main().catch((...args) => { + console.error(`ERROR! Could not generate schema`, ...args); + process.exit(1); +}); diff --git a/apps/backend/scripts/test.ts b/apps/backend/scripts/test.ts new file mode 100644 index 000000000..e0aa2a769 --- /dev/null +++ b/apps/backend/scripts/test.ts @@ -0,0 +1,238 @@ +import { EndpointTransforms, EndpointsSchema, ParsedResponseFromSchema, RawEndpointsHandlers, TransformFn, createEndpointHandlersFromRawEndpoints, createMigrationEndpointHandlers } from "@/route-handlers/migration-handler"; +import { yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields"; +import { NextRequest, NextResponse } from "next/server"; + +const schema1 = { + '/users': { + 'POST': { + 'default': { + input: { + query: yupObject({}).defined(), + body: yupObject({ + fullName: yupString().defined(), + }).defined(), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + id: yupString().defined(), + fullName: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/tokens': { + 'POST': { + 'default': { + input: { + query: yupObject({}).defined(), + body: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({}).defined(), + }, + }, + }, + }, + '/same': { + 'POST': { + 'default': { + input: { + query: yupObject({ + same: yupString().defined(), + }).defined(), + body: yupObject({ + same: yupString().defined(), + }).defined(), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + same: yupString().defined(), + }).defined(), + }, + }, + }, + }, +} as const satisfies EndpointsSchema; + + +const schema2 = { + '/users': { + 'POST': { + 'default': { + input: { + query: yupObject({}).defined(), + body: yupObject({ + firstName: yupString().defined(), + lastName: yupString().defined(), + }).defined(), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + id: yupString().defined(), + }).defined(), + }, + }, + }, + 'GET': { + 'default': { + input: { + query: yupObject({}).defined(), + body: yupObject({}).defined(), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({}).defined(), + }, + }, + }, + }, + '/same': { + 'POST': { + 'default': { + input: { + query: yupObject({ + same: yupString().defined(), + }).defined(), + body: yupObject({ + same: yupString().defined(), + }).defined(), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + same: yupString().defined(), + }).defined(), + }, + }, + }, + }, +} as const satisfies EndpointsSchema; + +const exampleRawEndpointHandlers = { + '/users': { + 'POST': async (req: NextRequest) => { + return NextResponse.json({ id: 'example-id' }); + }, + }, + '/tokens': { + 'POST': async (req: NextRequest) => { + return NextResponse.json({ test: 'example-token' }); + }, + }, + '/same': { + 'POST': async (req: NextRequest) => { + return NextResponse.json({ same: 'same' }); + }, + }, +} satisfies RawEndpointsHandlers; + + +const endpointHandlers2 = createEndpointHandlersFromRawEndpoints(exampleRawEndpointHandlers, schema2); +const endpointHandlers1 = createMigrationEndpointHandlers(schema1, schema2, endpointHandlers2, { + '/users': { + 'POST': { + 'default': async ({ req, newEndpointHandlers }) => { + const result = await newEndpointHandlers['/users']['POST']['default']({ + body: { + firstName: req.body.fullName.split(' ')[0], + lastName: req.body.fullName.split(' ')[1], + }, + query: {}, + headers: {}, + method: 'POST', + url: 'http://localhost:3000/users', + }); + + return { + statusCode: 200, + headers: {}, + body: { + id: (result.body as any).id, + fullName: req.body.fullName, + }, + bodyType: 'json', + }; + }, + }, + }, + '/tokens': { + 'POST': { + 'default': async ({ req, newEndpointHandlers }) => { + return { + statusCode: 200, + headers: {}, + body: { + test: 'example-token', + }, + bodyType: 'json', + }; + }, + }, + } +}); + +type x = EndpointTransforms; + +const y = null as unknown as x; + +const z = null as unknown as x['/users']['POST']['default']; + +type a = Awaited>>; + +type b = ParsedResponseFromSchema + +const c = null as unknown as b; + +// endpointHandlers1['/tokens']['POST']['default']({ +// url: 'http://localhost:3000/tokens', +// method: 'POST', +// headers: {}, +// body: {}, +// query: {}, +// }).then((res) => { +// console.log(res); +// }).catch((err) => { +// console.error(err); +// }); + + +endpointHandlers1['/users']['POST']['default']({ + body: { + fullName: 'John Doe', + }, + query: {}, + headers: {}, + method: 'POST', + url: 'http://localhost:3000/users', +}).then((res) => { + console.log(res); +}).catch((err) => { + console.error(err); +}); + +// endpointHandlers1['/same']['POST']['default']({ +// body: { +// same: 'same', +// }, +// query: { +// same: 'same', +// }, +// headers: {}, +// method: 'POST', +// url: 'http://localhost:3000/same', +// }).then((res) => { +// console.log(res); +// }).catch((err) => { +// console.error(err); +// }); diff --git a/apps/backend/src/app/api/v2/[...all]/route.tsx b/apps/backend/src/app/api/v2/[...all]/route.tsx new file mode 100644 index 000000000..686ec5587 --- /dev/null +++ b/apps/backend/src/app/api/v2/[...all]/route.tsx @@ -0,0 +1,5 @@ +import { NextRequest, NextResponse } from "next/server"; + +export const GET = async (req: NextRequest) => { + return NextResponse.json({ 'hi': 'asdf' }); +}; diff --git a/apps/backend/src/app/api/v2/imports.ts b/apps/backend/src/app/api/v2/imports.ts new file mode 100644 index 000000000..9d746c15a --- /dev/null +++ b/apps/backend/src/app/api/v2/imports.ts @@ -0,0 +1,282 @@ +import { GET as iGet } from '../../api/v1/route'; +import { GET as iUsersGet } from '../../api/v1/users/route'; +import { POST as iUsersPost } from '../../api/v1/users/route'; +import { GET as iTeamsGet } from '../../api/v1/teams/route'; +import { POST as iTeamsPost } from '../../api/v1/teams/route'; +import { GET as iTeamPermissionDefinitionsGet } from '../../api/v1/team-permission-definitions/route'; +import { POST as iTeamPermissionDefinitionsPost } from '../../api/v1/team-permission-definitions/route'; +import { GET as iTeamMemberProfilesGet } from '../../api/v1/team-member-profiles/route'; +import { GET as iTeamPermissionsGet } from '../../api/v1/team-permissions/route'; +import { GET as iTeamInvitationsGet } from '../../api/v1/team-invitations/route'; +import { GET as iEmailTemplatesGet } from '../../api/v1/email-templates/route'; +import { GET as iContactChannelsGet } from '../../api/v1/contact-channels/route'; +import { POST as iContactChannelsPost } from '../../api/v1/contact-channels/route'; +import { POST as iCheckVersionPost } from '../../api/v1/check-version/route'; +import { POST as iCheckFeatureSupportPost } from '../../api/v1/check-feature-support/route'; +import { POST as iWebhooksSvixTokenPost } from '../../api/v1/webhooks/svix-token/route'; +import { GET as iUsersMeGet } from '../../api/v1/users/me/route'; +import { DELETE as iUsersMeDelete } from '../../api/v1/users/me/route'; +import { PATCH as iUsersMePatch } from '../../api/v1/users/me/route'; +import { GET as iTeamsTeamIdGet } from '../../api/v1/teams/[team_id]/route'; +import { DELETE as iTeamsTeamIdDelete } from '../../api/v1/teams/[team_id]/route'; +import { PATCH as iTeamsTeamIdPatch } from '../../api/v1/teams/[team_id]/route'; +import { GET as iUsersUserIdGet } from '../../api/v1/users/[user_id]/route'; +import { DELETE as iUsersUserIdDelete } from '../../api/v1/users/[user_id]/route'; +import { PATCH as iUsersUserIdPatch } from '../../api/v1/users/[user_id]/route'; +import { DELETE as iTeamPermissionDefinitionsPermissionIdDelete } from '../../api/v1/team-permission-definitions/[permission_id]/route'; +import { PATCH as iTeamPermissionDefinitionsPermissionIdPatch } from '../../api/v1/team-permission-definitions/[permission_id]/route'; +import { POST as iTeamInvitationsSendCodePost } from '../../api/v1/team-invitations/send-code/route'; +import { POST as iTeamInvitationsAcceptPost } from '../../api/v1/team-invitations/accept/route'; +import { DELETE as iTeamInvitationsIdDelete } from '../../api/v1/team-invitations/[id]/route'; +import { GET as iProjectsCurrentGet } from '../../api/v1/projects/current/route'; +import { DELETE as iProjectsCurrentDelete } from '../../api/v1/projects/current/route'; +import { PATCH as iProjectsCurrentPatch } from '../../api/v1/projects/current/route'; +import { POST as iInternalSendTestEmailPost } from '../../api/v1/internal/send-test-email/route'; +import { GET as iInternalProjectsGet } from '../../api/v1/internal/projects/route'; +import { POST as iInternalProjectsPost } from '../../api/v1/internal/projects/route'; +import { GET as iInternalMetricsGet } from '../../api/v1/internal/metrics/route'; +import { GET as iInternalApiKeysGet } from '../../api/v1/internal/api-keys/route'; +import { POST as iInternalApiKeysPost } from '../../api/v1/internal/api-keys/route'; +import { GET as iEmailTemplatesTypeGet } from '../../api/v1/email-templates/[type]/route'; +import { DELETE as iEmailTemplatesTypeDelete } from '../../api/v1/email-templates/[type]/route'; +import { PATCH as iEmailTemplatesTypePatch } from '../../api/v1/email-templates/[type]/route'; +import { POST as iContactChannelsSendVerificationCodePost } from '../../api/v1/contact-channels/send-verification-code/route'; +import { POST as iContactChannelsVerifyPost } from '../../api/v1/contact-channels/verify/route'; +import { POST as iAuthSessionsPost } from '../../api/v1/auth/sessions/route'; +import { POST as iTeamMembershipsTeamIdUserIdPost } from '../../api/v1/team-memberships/[team_id]/[user_id]/route'; +import { DELETE as iTeamMembershipsTeamIdUserIdDelete } from '../../api/v1/team-memberships/[team_id]/[user_id]/route'; +import { GET as iTeamMemberProfilesTeamIdUserIdGet } from '../../api/v1/team-member-profiles/[team_id]/[user_id]/route'; +import { PATCH as iTeamMemberProfilesTeamIdUserIdPatch } from '../../api/v1/team-member-profiles/[team_id]/[user_id]/route'; +import { POST as iTeamInvitationsAcceptDetailsPost } from '../../api/v1/team-invitations/accept/details/route'; +import { POST as iTeamInvitationsAcceptCheckCodePost } from '../../api/v1/team-invitations/accept/check-code/route'; +import { POST as iIntegrationsNeonWebhooksPost } from '../../api/v1/integrations/neon/webhooks/route'; +import { GET as iInternalApiKeysApiKeyIdGet } from '../../api/v1/internal/api-keys/[api_key_id]/route'; +import { PATCH as iInternalApiKeysApiKeyIdPatch } from '../../api/v1/internal/api-keys/[api_key_id]/route'; +import { GET as iIntegrationsNeonOauthGet } from '../../api/v1/integrations/neon/oauth/route'; +import { GET as iIntegrationsNeonOauthProvidersGet } from '../../api/v1/integrations/neon/oauth-providers/route'; +import { POST as iIntegrationsNeonOauthProvidersPost } from '../../api/v1/integrations/neon/oauth-providers/route'; +import { POST as iContactChannelsVerifyCheckCodePost } from '../../api/v1/contact-channels/verify/check-code/route'; +import { GET as iIntegrationsNeonApiKeysGet } from '../../api/v1/integrations/neon/api-keys/route'; +import { POST as iIntegrationsNeonApiKeysPost } from '../../api/v1/integrations/neon/api-keys/route'; +import { GET as iContactChannelsUserIdContactChannelIdGet } from '../../api/v1/contact-channels/[user_id]/[contact_channel_id]/route'; +import { DELETE as iContactChannelsUserIdContactChannelIdDelete } from '../../api/v1/contact-channels/[user_id]/[contact_channel_id]/route'; +import { PATCH as iContactChannelsUserIdContactChannelIdPatch } from '../../api/v1/contact-channels/[user_id]/[contact_channel_id]/route'; +import { DELETE as iAuthSessionsCurrentDelete } from '../../api/v1/auth/sessions/current/route'; +import { POST as iAuthPasswordUpdatePost } from '../../api/v1/auth/password/update/route'; +import { POST as iAuthPasswordSignUpPost } from '../../api/v1/auth/password/sign-up/route'; +import { POST as iAuthPasswordSignInPost } from '../../api/v1/auth/password/sign-in/route'; +import { POST as iAuthPasswordSetPost } from '../../api/v1/auth/password/set/route'; +import { POST as iAuthPasswordSendResetCodePost } from '../../api/v1/auth/password/send-reset-code/route'; +import { POST as iAuthPasswordResetPost } from '../../api/v1/auth/password/reset/route'; +import { POST as iAuthPasskeySignInPost } from '../../api/v1/auth/passkey/sign-in/route'; +import { POST as iAuthPasskeyInitiatePasskeyRegistrationPost } from '../../api/v1/auth/passkey/initiate-passkey-registration/route'; +import { POST as iAuthPasskeyInitiatePasskeyAuthenticationPost } from '../../api/v1/auth/passkey/initiate-passkey-authentication/route'; +import { POST as iAuthPasskeyRegisterPost } from '../../api/v1/auth/passkey/register/route'; +import { POST as iAuthOtpSignInPost } from '../../api/v1/auth/otp/sign-in/route'; +import { POST as iAuthOtpSendSignInCodePost } from '../../api/v1/auth/otp/send-sign-in-code/route'; +import { POST as iAuthOauthTokenPost } from '../../api/v1/auth/oauth/token/route'; +import { POST as iAuthMfaSignInPost } from '../../api/v1/auth/mfa/sign-in/route'; +import { POST as iTeamPermissionsTeamIdUserIdPermissionIdPost } from '../../api/v1/team-permissions/[team_id]/[user_id]/[permission_id]/route'; +import { DELETE as iTeamPermissionsTeamIdUserIdPermissionIdDelete } from '../../api/v1/team-permissions/[team_id]/[user_id]/[permission_id]/route'; +import { POST as iIntegrationsNeonProjectsProvisionPost } from '../../api/v1/integrations/neon/projects/provision/route'; +import { POST as iIntegrationsNeonOauthTokenPost } from '../../api/v1/integrations/neon/oauth/token/route'; +import { GET as iIntegrationsNeonOauthAuthorizeGet } from '../../api/v1/integrations/neon/oauth/authorize/route'; +import { DELETE as iIntegrationsNeonOauthProvidersOauthProviderIdDelete } from '../../api/v1/integrations/neon/oauth-providers/[oauth_provider_id]/route'; +import { PATCH as iIntegrationsNeonOauthProvidersOauthProviderIdPatch } from '../../api/v1/integrations/neon/oauth-providers/[oauth_provider_id]/route'; +import { POST as iIntegrationsNeonInternalConfirmPost } from '../../api/v1/integrations/neon/internal/confirm/route'; +import { POST as iConnectedAccountsUserIdProviderIdAccessTokenPost } from '../../api/v1/connected-accounts/[user_id]/[provider_id]/access-token/route'; +import { GET as iIntegrationsNeonApiKeysApiKeyIdGet } from '../../api/v1/integrations/neon/api-keys/[api_key_id]/route'; +import { PATCH as iIntegrationsNeonApiKeysApiKeyIdPatch } from '../../api/v1/integrations/neon/api-keys/[api_key_id]/route'; +import { POST as iContactChannelsUserIdContactChannelIdSendVerificationCodePost } from '../../api/v1/contact-channels/[user_id]/[contact_channel_id]/send-verification-code/route'; +import { POST as iAuthSessionsCurrentRefreshPost } from '../../api/v1/auth/sessions/current/refresh/route'; +import { POST as iAuthPasswordResetCheckCodePost } from '../../api/v1/auth/password/reset/check-code/route'; +import { GET as iAuthOauthAuthorizeProviderIdGet } from '../../api/v1/auth/oauth/authorize/[provider_id]/route'; +import { POST as iAuthOtpSignInCheckCodePost } from '../../api/v1/auth/otp/sign-in/check-code/route'; +import { GET as iAuthOauthCallbackProviderIdGet } from '../../api/v1/auth/oauth/callback/[provider_id]/route'; +import { POST as iAuthOauthCallbackProviderIdPost } from '../../api/v1/auth/oauth/callback/[provider_id]/route'; +import { POST as iIntegrationsNeonProjectsTransferInitiatePost } from '../../api/v1/integrations/neon/projects/transfer/initiate/route'; +import { POST as iIntegrationsNeonProjectsTransferConfirmPost } from '../../api/v1/integrations/neon/projects/transfer/confirm/route'; +import { GET as iIntegrationsNeonOauthIdpRouteGet } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { POST as iIntegrationsNeonOauthIdpRoutePost } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { PUT as iIntegrationsNeonOauthIdpRoutePut } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { DELETE as iIntegrationsNeonOauthIdpRouteDelete } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { PATCH as iIntegrationsNeonOauthIdpRoutePatch } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { OPTIONS as iIntegrationsNeonOauthIdpRouteOptions } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { HEAD as iIntegrationsNeonOauthIdpRouteHead } from '../../api/v1/integrations/neon/oauth/idp/[[...route]]/route'; +import { POST as iAuthOauthConnectedAccountsProviderIdAccessTokenPost } from '../../api/v1/auth/oauth/connected-accounts/[provider_id]/access-token/route'; + +export const endpoints = { + '/': { GET: iGet }, + '/users': { GET: iUsersGet, POST: iUsersPost }, + '/teams': { GET: iTeamsGet, POST: iTeamsPost }, + '/team-permission-definitions': { + GET: iTeamPermissionDefinitionsGet, + POST: iTeamPermissionDefinitionsPost, + }, + '/team-member-profiles': { GET: iTeamMemberProfilesGet }, + '/team-permissions': { GET: iTeamPermissionsGet }, + '/team-invitations': { GET: iTeamInvitationsGet }, + '/email-templates': { GET: iEmailTemplatesGet }, + '/contact-channels': { GET: iContactChannelsGet, POST: iContactChannelsPost }, + '/check-version': { POST: iCheckVersionPost }, + '/check-feature-support': { POST: iCheckFeatureSupportPost }, + '/webhooks/svix-token': { POST: iWebhooksSvixTokenPost }, + '/users/me': { + GET: iUsersMeGet, + DELETE: iUsersMeDelete, + PATCH: iUsersMePatch, + }, + '/teams/[team_id]': { + GET: iTeamsTeamIdGet, + DELETE: iTeamsTeamIdDelete, + PATCH: iTeamsTeamIdPatch, + }, + '/users/[user_id]': { + GET: iUsersUserIdGet, + DELETE: iUsersUserIdDelete, + PATCH: iUsersUserIdPatch, + }, + '/team-permission-definitions/[permission_id]': { + DELETE: iTeamPermissionDefinitionsPermissionIdDelete, + PATCH: iTeamPermissionDefinitionsPermissionIdPatch, + }, + '/team-invitations/send-code': { POST: iTeamInvitationsSendCodePost }, + '/team-invitations/accept': { POST: iTeamInvitationsAcceptPost }, + '/team-invitations/[id]': { DELETE: iTeamInvitationsIdDelete }, + '/projects/current': { + GET: iProjectsCurrentGet, + DELETE: iProjectsCurrentDelete, + PATCH: iProjectsCurrentPatch, + }, + '/internal/send-test-email': { POST: iInternalSendTestEmailPost }, + '/internal/projects': { + GET: iInternalProjectsGet, + POST: iInternalProjectsPost, + }, + '/internal/metrics': { GET: iInternalMetricsGet }, + '/internal/api-keys': { + GET: iInternalApiKeysGet, + POST: iInternalApiKeysPost, + }, + '/email-templates/[type]': { + GET: iEmailTemplatesTypeGet, + DELETE: iEmailTemplatesTypeDelete, + PATCH: iEmailTemplatesTypePatch, + }, + '/contact-channels/send-verification-code': { + POST: iContactChannelsSendVerificationCodePost, + }, + '/contact-channels/verify': { POST: iContactChannelsVerifyPost }, + '/auth/sessions': { POST: iAuthSessionsPost }, + '/team-memberships/[team_id]/[user_id]': { + POST: iTeamMembershipsTeamIdUserIdPost, + DELETE: iTeamMembershipsTeamIdUserIdDelete, + }, + '/team-member-profiles/[team_id]/[user_id]': { + GET: iTeamMemberProfilesTeamIdUserIdGet, + PATCH: iTeamMemberProfilesTeamIdUserIdPatch, + }, + '/team-invitations/accept/details': { + POST: iTeamInvitationsAcceptDetailsPost, + }, + '/team-invitations/accept/check-code': { + POST: iTeamInvitationsAcceptCheckCodePost, + }, + '/integrations/neon/webhooks': { POST: iIntegrationsNeonWebhooksPost }, + '/internal/api-keys/[api_key_id]': { + GET: iInternalApiKeysApiKeyIdGet, + PATCH: iInternalApiKeysApiKeyIdPatch, + }, + '/integrations/neon/oauth': { GET: iIntegrationsNeonOauthGet }, + '/integrations/neon/oauth-providers': { + GET: iIntegrationsNeonOauthProvidersGet, + POST: iIntegrationsNeonOauthProvidersPost, + }, + '/contact-channels/verify/check-code': { + POST: iContactChannelsVerifyCheckCodePost, + }, + '/integrations/neon/api-keys': { + GET: iIntegrationsNeonApiKeysGet, + POST: iIntegrationsNeonApiKeysPost, + }, + '/contact-channels/[user_id]/[contact_channel_id]': { + GET: iContactChannelsUserIdContactChannelIdGet, + DELETE: iContactChannelsUserIdContactChannelIdDelete, + PATCH: iContactChannelsUserIdContactChannelIdPatch, + }, + '/auth/sessions/current': { DELETE: iAuthSessionsCurrentDelete }, + '/auth/password/update': { POST: iAuthPasswordUpdatePost }, + '/auth/password/sign-up': { POST: iAuthPasswordSignUpPost }, + '/auth/password/sign-in': { POST: iAuthPasswordSignInPost }, + '/auth/password/set': { POST: iAuthPasswordSetPost }, + '/auth/password/send-reset-code': { POST: iAuthPasswordSendResetCodePost }, + '/auth/password/reset': { POST: iAuthPasswordResetPost }, + '/auth/passkey/sign-in': { POST: iAuthPasskeySignInPost }, + '/auth/passkey/initiate-passkey-registration': { + POST: iAuthPasskeyInitiatePasskeyRegistrationPost, + }, + '/auth/passkey/initiate-passkey-authentication': { + POST: iAuthPasskeyInitiatePasskeyAuthenticationPost, + }, + '/auth/passkey/register': { POST: iAuthPasskeyRegisterPost }, + '/auth/otp/sign-in': { POST: iAuthOtpSignInPost }, + '/auth/otp/send-sign-in-code': { POST: iAuthOtpSendSignInCodePost }, + '/auth/oauth/token': { POST: iAuthOauthTokenPost }, + '/auth/mfa/sign-in': { POST: iAuthMfaSignInPost }, + '/team-permissions/[team_id]/[user_id]/[permission_id]': { + POST: iTeamPermissionsTeamIdUserIdPermissionIdPost, + DELETE: iTeamPermissionsTeamIdUserIdPermissionIdDelete, + }, + '/integrations/neon/projects/provision': { + POST: iIntegrationsNeonProjectsProvisionPost, + }, + '/integrations/neon/oauth/token': { POST: iIntegrationsNeonOauthTokenPost }, + '/integrations/neon/oauth/authorize': { + GET: iIntegrationsNeonOauthAuthorizeGet, + }, + '/integrations/neon/oauth-providers/[oauth_provider_id]': { + DELETE: iIntegrationsNeonOauthProvidersOauthProviderIdDelete, + PATCH: iIntegrationsNeonOauthProvidersOauthProviderIdPatch, + }, + '/integrations/neon/internal/confirm': { + POST: iIntegrationsNeonInternalConfirmPost, + }, + '/connected-accounts/[user_id]/[provider_id]/access-token': { + POST: iConnectedAccountsUserIdProviderIdAccessTokenPost, + }, + '/integrations/neon/api-keys/[api_key_id]': { + GET: iIntegrationsNeonApiKeysApiKeyIdGet, + PATCH: iIntegrationsNeonApiKeysApiKeyIdPatch, + }, + '/contact-channels/[user_id]/[contact_channel_id]/send-verification-code': { + POST: iContactChannelsUserIdContactChannelIdSendVerificationCodePost, + }, + '/auth/sessions/current/refresh': { POST: iAuthSessionsCurrentRefreshPost }, + '/auth/password/reset/check-code': { POST: iAuthPasswordResetCheckCodePost }, + '/auth/oauth/authorize/[provider_id]': { + GET: iAuthOauthAuthorizeProviderIdGet, + }, + '/auth/otp/sign-in/check-code': { POST: iAuthOtpSignInCheckCodePost }, + '/auth/oauth/callback/[provider_id]': { + GET: iAuthOauthCallbackProviderIdGet, + POST: iAuthOauthCallbackProviderIdPost, + }, + '/integrations/neon/projects/transfer/initiate': { + POST: iIntegrationsNeonProjectsTransferInitiatePost, + }, + '/integrations/neon/projects/transfer/confirm': { + POST: iIntegrationsNeonProjectsTransferConfirmPost, + }, + '/integrations/neon/oauth/idp/[[...route]]': { + GET: iIntegrationsNeonOauthIdpRouteGet, + POST: iIntegrationsNeonOauthIdpRoutePost, + PUT: iIntegrationsNeonOauthIdpRoutePut, + DELETE: iIntegrationsNeonOauthIdpRouteDelete, + PATCH: iIntegrationsNeonOauthIdpRoutePatch, + OPTIONS: iIntegrationsNeonOauthIdpRouteOptions, + HEAD: iIntegrationsNeonOauthIdpRouteHead, + }, + '/auth/oauth/connected-accounts/[provider_id]/access-token': { + POST: iAuthOauthConnectedAccountsProviderIdAccessTokenPost, + }, +}; diff --git a/apps/backend/src/app/api/v2/schema.ts b/apps/backend/src/app/api/v2/schema.ts new file mode 100644 index 000000000..7dbf3ff08 --- /dev/null +++ b/apps/backend/src/app/api/v2/schema.ts @@ -0,0 +1,5919 @@ +import { + yupObject, + yupArray, + yupString, + yupNumber, + yupBoolean, + yupMixed, +} from '@stackframe/stack-shared/dist/schema-fields'; + +export const endpointSchema = { + '/': { + GET: { + default: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'text', + body: yupString().defined(), + }, + }, + }, + }, + '/users': { + GET: { + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + server: { + input: { + body: yupObject({ + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().nullable(), + }).defined(), + ).optional(), + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().nullable(), + }).defined(), + ).optional(), + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/teams': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + client: { + input: { + body: yupObject({ + display_name: yupString().defined(), + creator_user_id: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + display_name: yupString().defined(), + creator_user_id: yupString().optional(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + display_name: yupString().defined(), + creator_user_id: yupString().optional(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + }, + }, + '/team-permission-definitions': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + description: yupString().optional(), + contained_permission_ids: yupArray( + yupString().defined(), + ).defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + admin: { + input: { + body: yupObject({ + id: yupString().defined(), + description: yupString().optional(), + contained_permission_ids: yupArray( + yupString().defined(), + ).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + description: yupString().optional(), + contained_permission_ids: yupArray(yupString().defined()).defined(), + }).defined(), + }, + }, + }, + }, + '/team-member-profiles': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + }, + '/team-permissions': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + user_id: yupString().defined(), + team_id: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + user_id: yupString().defined(), + team_id: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + user_id: yupString().defined(), + team_id: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + }, + '/team-invitations': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + team_id: yupString().defined(), + expires_at_millis: yupNumber().defined(), + recipient_email: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + team_id: yupString().defined(), + expires_at_millis: yupNumber().defined(), + recipient_email: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + team_id: yupString().defined(), + expires_at_millis: yupNumber().defined(), + recipient_email: yupString().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + }, + '/email-templates': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + type: yupString() + .optional() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + subject: yupString().defined(), + content: yupMixed().nullable(), + is_default: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + }, + '/contact-channels': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + client: { + input: { + body: yupObject({ + user_id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_primary: yupBoolean().optional(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + is_verified: yupBoolean().optional(), + user_id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_primary: yupBoolean().optional(), + }).optional(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + is_verified: yupBoolean().optional(), + user_id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_primary: yupBoolean().optional(), + }).optional(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/check-version': { + POST: { + default: { + input: { + body: yupObject({ clientVersion: yupString().defined() }).optional(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupMixed().defined(), + }, + }, + }, + }, + '/check-feature-support': { + POST: { + default: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'text', + body: yupString().defined(), + }, + }, + }, + }, + '/webhooks/svix-token': { + POST: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ token: yupString().defined() }).defined(), + }, + }, + }, + }, + '/users/me': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + selected_team: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + display_name: yupString().nullable(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + auth_with_email: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + selected_team_id: yupString().nullable(), + requires_totp_mfa: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + }, + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + client: { + input: { + body: yupObject({ + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + selected_team_id: yupString().optional().nullable(), + totp_secret_base64: yupString().optional().nullable(), + otp_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + selected_team: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + display_name: yupString().nullable(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + auth_with_email: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + selected_team_id: yupString().nullable(), + requires_totp_mfa: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + selected_team_id: yupString().optional().nullable(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + selected_team_id: yupString().optional().nullable(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/teams/[team_id]': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + }, + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + client: { + input: { + body: yupObject({ + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + add_current_user: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ team_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).defined(), + }, + }, + }, + }, + '/users/[user_id]': { + GET: { + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + }, + DELETE: { + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + server: { + input: { + body: yupObject({ + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + selected_team_id: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + display_name: yupString().optional().nullable(), + profile_image_url: yupString().optional().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + server_metadata: yupMixed().optional().nullable(), + primary_email: yupString().optional().nullable(), + primary_email_verified: yupBoolean().optional(), + primary_email_auth_enabled: yupBoolean().optional(), + passkey_auth_enabled: yupBoolean().optional(), + password: yupString().optional().nullable(), + password_hash: yupString().optional(), + otp_auth_enabled: yupBoolean().optional(), + totp_secret_base64: yupString().optional().nullable(), + selected_team_id: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + team_id: yupString().optional(), + limit: yupNumber().optional(), + cursor: yupString().optional(), + order_by: yupString().optional().oneOf(['signed_up_at']), + desc: yupBoolean().optional(), + query: yupString().optional(), + }).optional(), + params: yupObject({ user_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/team-permission-definitions/[permission_id]': { + DELETE: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + permission_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + id: yupString().optional(), + description: yupString().optional(), + contained_permission_ids: yupArray( + yupString().defined(), + ).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ + permission_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + description: yupString().optional(), + contained_permission_ids: yupArray(yupString().defined()).defined(), + }).defined(), + }, + }, + }, + }, + '/team-invitations/send-code': { + POST: { + client: { + input: { + body: yupObject({ + team_id: yupString().defined(), + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupBoolean().defined().oneOf([true]), + id: yupString().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + team_id: yupString().defined(), + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupBoolean().defined().oneOf([true]), + id: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + team_id: yupString().defined(), + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupBoolean().defined().oneOf([true]), + id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/team-invitations/accept': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({}).defined(), + }, + }, + }, + }, + '/team-invitations/[id]': { + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ team_id: yupString().defined() }).optional(), + params: yupObject({ id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + }, + '/projects/current': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + config: yupObject({ + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + config: yupObject({ + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + }, + DELETE: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + display_name: yupString().optional(), + description: yupString().optional().nullable(), + is_production_mode: yupBoolean().optional(), + config: yupObject({ + sign_up_enabled: yupBoolean().optional(), + credential_enabled: yupBoolean().optional(), + magic_link_enabled: yupBoolean().optional(), + passkey_enabled: yupBoolean().optional(), + client_team_creation_enabled: yupBoolean().optional(), + client_user_deletion_enabled: yupBoolean().optional(), + legacy_global_jwt_signing: yupBoolean().optional(), + allow_localhost: yupBoolean().optional(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).optional(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).optional(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).optional(), + create_team_on_sign_up: yupBoolean().optional(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + }).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + }, + }, + '/internal/send-test-email': { + POST: { + admin: { + input: { + body: yupObject({ + recipient_email: yupString().defined(), + email_config: yupObject({ + host: yupString().defined(), + port: yupNumber().defined(), + username: yupString().defined(), + password: yupString().defined(), + sender_name: yupString().defined(), + sender_email: yupString().defined(), + }).defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupBoolean().defined(), + error_message: yupString().optional(), + }).defined(), + }, + }, + }, + }, + '/internal/projects': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + client: { + input: { + body: yupObject({ + display_name: yupString().defined(), + description: yupString().optional().nullable(), + is_production_mode: yupBoolean().optional(), + config: yupObject({ + sign_up_enabled: yupBoolean().optional(), + credential_enabled: yupBoolean().optional(), + magic_link_enabled: yupBoolean().optional(), + passkey_enabled: yupBoolean().optional(), + client_team_creation_enabled: yupBoolean().optional(), + client_user_deletion_enabled: yupBoolean().optional(), + legacy_global_jwt_signing: yupBoolean().optional(), + allow_localhost: yupBoolean().optional(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).optional(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).optional(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).optional(), + create_team_on_sign_up: yupBoolean().optional(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + }).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + display_name: yupString().defined(), + description: yupString().optional().nullable(), + is_production_mode: yupBoolean().optional(), + config: yupObject({ + sign_up_enabled: yupBoolean().optional(), + credential_enabled: yupBoolean().optional(), + magic_link_enabled: yupBoolean().optional(), + passkey_enabled: yupBoolean().optional(), + client_team_creation_enabled: yupBoolean().optional(), + client_user_deletion_enabled: yupBoolean().optional(), + legacy_global_jwt_signing: yupBoolean().optional(), + allow_localhost: yupBoolean().optional(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).optional(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).optional(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).optional(), + create_team_on_sign_up: yupBoolean().optional(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + }).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + display_name: yupString().defined(), + description: yupString().optional().nullable(), + is_production_mode: yupBoolean().optional(), + config: yupObject({ + sign_up_enabled: yupBoolean().optional(), + credential_enabled: yupBoolean().optional(), + magic_link_enabled: yupBoolean().optional(), + passkey_enabled: yupBoolean().optional(), + client_team_creation_enabled: yupBoolean().optional(), + client_user_deletion_enabled: yupBoolean().optional(), + legacy_global_jwt_signing: yupBoolean().optional(), + allow_localhost: yupBoolean().optional(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).optional(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).optional(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).optional(), + create_team_on_sign_up: yupBoolean().optional(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).optional(), + }).optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ projectId: yupString().optional() }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + display_name: yupString().defined(), + description: yupString().defined(), + created_at_millis: yupNumber().defined(), + user_count: yupNumber().defined(), + is_production_mode: yupBoolean().defined(), + config: yupObject({ + id: yupString().defined(), + allow_localhost: yupBoolean().defined(), + sign_up_enabled: yupBoolean().defined(), + credential_enabled: yupBoolean().defined(), + magic_link_enabled: yupBoolean().defined(), + passkey_enabled: yupBoolean().defined(), + legacy_global_jwt_signing: yupBoolean().defined(), + client_team_creation_enabled: yupBoolean().defined(), + client_user_deletion_enabled: yupBoolean().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + enabled: yupBoolean().defined(), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).defined(), + ).defined(), + enabled_oauth_providers: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).defined(), + ).defined(), + domains: yupArray( + yupObject({ + domain: yupString().defined(), + handler_path: yupString().defined(), + }).defined(), + ).defined(), + email_config: yupObject({ + type: yupString().defined().oneOf(['shared', 'standard']), + host: yupString().optional(), + port: yupNumber().optional(), + username: yupString().optional(), + password: yupString().optional(), + sender_name: yupString().optional(), + sender_email: yupString().optional(), + }).defined(), + create_team_on_sign_up: yupBoolean().defined(), + team_creator_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + team_member_default_permissions: yupArray( + yupObject({ id: yupString().defined() }).defined(), + ).defined(), + }).defined(), + }).defined(), + }, + }, + }, + }, + '/internal/metrics': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + total_users: yupNumber().defined(), + daily_users: yupArray( + yupObject({ + date: yupString().defined(), + activity: yupNumber().defined(), + }).defined(), + ).defined(), + daily_active_users: yupArray( + yupObject({ + date: yupString().defined(), + activity: yupNumber().defined(), + }).defined(), + ).defined(), + users_by_country: yupMixed().defined(), + recently_registered: yupMixed().defined(), + recently_active: yupMixed().defined(), + login_methods: yupMixed().defined(), + }).defined(), + }, + }, + }, + }, + '/internal/api-keys': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + admin: { + input: { + body: yupObject({ + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + has_publishable_client_key: yupBoolean().defined(), + has_secret_server_key: yupBoolean().defined(), + has_super_secret_admin_key: yupBoolean().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + publishable_client_key: yupString().optional(), + secret_server_key: yupString().optional(), + super_secret_admin_key: yupString().optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).defined(), + }, + }, + }, + }, + '/email-templates/[type]': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + subject: yupString().defined(), + content: yupMixed().nullable(), + is_default: yupBoolean().defined(), + }).defined(), + }, + }, + }, + DELETE: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + content: yupMixed().optional(), + subject: yupString().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + type: yupString() + .defined() + .oneOf([ + 'email_verification', + 'password_reset', + 'magic_link', + 'team_invitation', + ]), + subject: yupString().defined(), + content: yupMixed().nullable(), + is_default: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/contact-channels/send-verification-code': { + POST: { + client: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + server: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + admin: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/contact-channels/verify': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/sessions': { + POST: { + server: { + input: { + body: yupObject({ + user_id: yupString().defined(), + expires_in_millis: yupNumber().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + refresh_token: yupString().defined(), + access_token: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + user_id: yupString().defined(), + expires_in_millis: yupNumber().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + refresh_token: yupString().defined(), + access_token: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/team-memberships/[team_id]/[user_id]': { + POST: { + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + }, + '/team-member-profiles/[team_id]/[user_id]': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + }, + PATCH: { + client: { + input: { + body: yupObject({ + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + display_name: yupString().optional(), + profile_image_url: yupString().optional().nullable(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + team_id: yupString().optional(), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user: yupObject({ + id: yupString().defined(), + primary_email: yupString().nullable(), + primary_email_verified: yupBoolean().defined(), + primary_email_auth_enabled: yupBoolean().defined(), + display_name: yupString().nullable(), + selected_team: yupObject({ + created_at_millis: yupNumber().defined(), + server_metadata: yupMixed().optional().nullable(), + id: yupString().defined(), + display_name: yupString().defined(), + profile_image_url: yupString().nullable(), + client_metadata: yupMixed().optional().nullable(), + client_read_only_metadata: yupMixed().optional().nullable(), + }).nullable(), + selected_team_id: yupString().nullable(), + profile_image_url: yupString().nullable(), + signed_up_at_millis: yupNumber().defined(), + has_password: yupBoolean().defined(), + otp_auth_enabled: yupBoolean().defined(), + passkey_auth_enabled: yupBoolean().defined(), + client_metadata: yupMixed().nullable(), + client_read_only_metadata: yupMixed().nullable(), + server_metadata: yupMixed().nullable(), + last_active_at_millis: yupNumber().defined(), + oauth_providers: yupArray( + yupObject({ + id: yupString().defined(), + account_id: yupString().defined(), + email: yupString().optional().nullable(), + }).defined(), + ).defined(), + auth_with_email: yupBoolean().defined(), + requires_totp_mfa: yupBoolean().defined(), + }).defined(), + team_id: yupString().defined(), + user_id: yupString().defined(), + display_name: yupString().nullable(), + profile_image_url: yupString().nullable(), + }).defined(), + }, + }, + }, + }, + '/team-invitations/accept/details': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + team_id: yupString().defined(), + team_display_name: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/team-invitations/accept/check-code': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + is_code_valid: yupBoolean().defined().oneOf([true]), + }).defined(), + }, + }, + }, + }, + '/integrations/neon/webhooks': { + POST: { + default: { + input: { + body: yupObject({ + url: yupString().defined(), + description: yupString().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ secret: yupString().defined() }).defined(), + }, + }, + }, + }, + '/internal/api-keys/[api_key_id]': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + description: yupString().optional(), + revoked: yupBoolean().optional().oneOf([true]), + }).defined(), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + }, + }, + }, + }, + '/integrations/neon/oauth': { + GET: { + default: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'text', + body: yupString().defined(), + }, + }, + }, + }, + '/integrations/neon/oauth-providers': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ + oauth_provider_id: yupString() + .optional() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).optional(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + admin: { + input: { + body: yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + type: yupString().optional().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).optional(), + query: yupObject({}), + params: yupObject({ + oauth_provider_id: yupString() + .optional() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).optional(), + }, + }, + }, + }, + '/contact-channels/verify/check-code': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + is_code_valid: yupBoolean().defined().oneOf([true]), + }).defined(), + }, + }, + }, + }, + '/integrations/neon/api-keys': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().optional() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + items: yupArray( + yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + ).defined(), + is_paginated: yupBoolean().defined(), + pagination: yupObject({ + next_cursor: yupString().nullable(), + }).optional(), + }).defined(), + }, + }, + }, + POST: { + admin: { + input: { + body: yupObject({ + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + has_publishable_client_key: yupBoolean().defined(), + has_secret_server_key: yupBoolean().defined(), + has_super_secret_admin_key: yupBoolean().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + publishable_client_key: yupString().optional(), + secret_server_key: yupString().optional(), + super_secret_admin_key: yupString().optional(), + }).defined(), + }, + }, + }, + }, + '/contact-channels/[user_id]/[contact_channel_id]': { + GET: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + }, + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + client: { + input: { + body: yupObject({ + value: yupString().optional(), + type: yupString().optional().oneOf(['email']), + used_for_auth: yupBoolean().optional(), + is_primary: yupBoolean().optional(), + }).defined(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + is_verified: yupBoolean().optional(), + value: yupString().optional(), + type: yupString().optional().oneOf(['email']), + used_for_auth: yupBoolean().optional(), + is_primary: yupBoolean().optional(), + }).optional(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + is_verified: yupBoolean().optional(), + value: yupString().optional(), + type: yupString().optional().oneOf(['email']), + used_for_auth: yupBoolean().optional(), + is_primary: yupBoolean().optional(), + }).optional(), + query: yupObject({ + user_id: yupString().optional(), + contact_channel_id: yupString().optional(), + }).optional(), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + user_id: yupString().defined(), + id: yupString().defined(), + value: yupString().defined(), + type: yupString().defined().oneOf(['email']), + used_for_auth: yupBoolean().defined(), + is_verified: yupBoolean().defined(), + is_primary: yupBoolean().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/sessions/current': { + DELETE: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/password/update': { + POST: { + client: { + input: { + body: yupObject({ + old_password: yupString().defined(), + new_password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + server: { + input: { + body: yupObject({ + old_password: yupString().defined(), + new_password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + admin: { + input: { + body: yupObject({ + old_password: yupString().defined(), + new_password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/password/sign-up': { + POST: { + client: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + verification_callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + verification_callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + verification_callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/password/sign-in': { + POST: { + client: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + email: yupString().defined(), + password: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + access_token: yupString().defined(), + refresh_token: yupString().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/password/set': { + POST: { + client: { + input: { + body: yupObject({ password: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + server: { + input: { + body: yupObject({ password: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + admin: { + input: { + body: yupObject({ password: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/password/send-reset-code': { + POST: { + client: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupString() + .defined() + .oneOf(['maybe, only if user with e-mail exists']), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupString() + .defined() + .oneOf(['maybe, only if user with e-mail exists']), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + success: yupString() + .defined() + .oneOf(['maybe, only if user with e-mail exists']), + }).defined(), + }, + }, + }, + }, + '/auth/password/reset': { + POST: { + default: { + input: { + body: yupObject({ + password: yupString().defined(), + code: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/passkey/sign-in': { + POST: { + default: { + input: { + body: yupObject({ + authentication_response: yupMixed().defined(), + code: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + refresh_token: yupString().defined(), + access_token: yupString().defined(), + is_new_user: yupBoolean().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/passkey/initiate-passkey-registration': { + POST: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).optional(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).optional(), + }, + }, + }, + }, + '/auth/passkey/initiate-passkey-authentication': { + POST: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + options_json: yupMixed().defined(), + code: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/passkey/register': { + POST: { + default: { + input: { + body: yupObject({ + credential: yupMixed().defined(), + code: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ user_handle: yupString().defined() }).optional(), + }, + }, + }, + }, + '/auth/otp/sign-in': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + refresh_token: yupString().defined(), + access_token: yupString().defined(), + is_new_user: yupBoolean().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/auth/otp/send-sign-in-code': { + POST: { + client: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ nonce: yupString().defined() }).defined(), + }, + }, + server: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ nonce: yupString().defined() }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + email: yupString().defined(), + callback_url: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ nonce: yupString().defined() }).defined(), + }, + }, + }, + }, + '/auth/oauth/token': { + POST: { + default: { + input: { + body: yupObject({ + grant_type: yupString() + .defined() + .oneOf(['authorization_code', 'refresh_token']), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [], + bodyType: 'json', + headers: yupMixed().defined(), + body: yupMixed().defined(), + }, + }, + }, + }, + '/auth/mfa/sign-in': { + POST: { + default: { + input: { + body: yupObject({ + type: yupString().defined().oneOf(['totp']), + totp: yupString().defined(), + code: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + refresh_token: yupString().defined(), + access_token: yupString().defined(), + is_new_user: yupBoolean().defined(), + user_id: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/team-permissions/[team_id]/[user_id]/[permission_id]': { + POST: { + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + user_id: yupString().defined(), + team_id: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString().defined(), + user_id: yupString().defined(), + team_id: yupString().defined(), + }).defined(), + }, + }, + }, + DELETE: { + server: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + permission_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({ + team_id: yupString().optional(), + user_id: yupString().optional(), + permission_id: yupString().optional(), + recursive: yupString().optional().oneOf(['true', 'false']), + }).optional(), + params: yupObject({ + team_id: yupString().defined(), + user_id: yupString().defined(), + permission_id: yupString().defined(), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + }, + '/integrations/neon/projects/provision': { + POST: { + default: { + input: { + body: yupObject({ display_name: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + project_id: yupString().defined(), + super_secret_admin_key: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/integrations/neon/oauth/token': { + POST: { + default: { + input: { + body: yupObject({ + grant_type: yupString().defined().oneOf(['authorization_code']), + code: yupString().defined(), + code_verifier: yupString().defined(), + redirect_uri: yupString().defined(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: {}, + }, + }, + }, + '/integrations/neon/oauth/authorize': { + GET: { + default: { + input: { + body: yupObject({}), + query: yupObject({ + client_id: yupString().defined(), + redirect_uri: yupString().defined(), + state: yupString().defined(), + code_challenge: yupString().defined(), + code_challenge_method: yupString().defined().oneOf(['S256']), + response_type: yupString().defined().oneOf(['code']), + }).defined(), + params: yupObject({}), + }, + output: {}, + }, + }, + }, + '/integrations/neon/oauth-providers/[oauth_provider_id]': { + DELETE: { + admin: { + input: { + body: yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).optional(), + query: yupObject({}), + params: yupObject({ + oauth_provider_id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'success', + headers: yupObject({}).optional(), + body: yupMixed().optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + type: yupString().optional().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).optional(), + query: yupObject({}), + params: yupObject({ + oauth_provider_id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + id: yupString() + .defined() + .oneOf([ + 'google', + 'github', + 'microsoft', + 'spotify', + 'facebook', + 'discord', + 'gitlab', + 'bitbucket', + 'linkedin', + 'apple', + 'x', + ]), + type: yupString().defined().oneOf(['shared', 'standard']), + client_id: yupString().optional(), + client_secret: yupString().optional(), + facebook_config_id: yupString().optional(), + microsoft_tenant_id: yupString().optional(), + }).optional(), + }, + }, + }, + }, + '/integrations/neon/internal/confirm': { + POST: { + server: { + input: { + body: yupObject({ + interaction_uid: yupString().defined(), + project_id: yupString().defined(), + neon_project_name: yupString().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + authorization_code: yupString().defined(), + }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ + interaction_uid: yupString().defined(), + project_id: yupString().defined(), + neon_project_name: yupString().optional(), + }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + authorization_code: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/connected-accounts/[user_id]/[provider_id]/access-token': { + POST: { + client: { + input: { + body: yupObject({ scope: yupString().optional() }).defined(), + query: yupObject({}), + params: yupObject({ + provider_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + server: { + input: { + body: yupObject({ scope: yupString().optional() }).defined(), + query: yupObject({}), + params: yupObject({ + provider_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + admin: { + input: { + body: yupObject({ scope: yupString().optional() }).defined(), + query: yupObject({}), + params: yupObject({ + provider_id: yupString().optional(), + user_id: yupString().optional(), + }).optional(), + }, + output: { + statusCode: [201], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + }, + }, + '/integrations/neon/api-keys/[api_key_id]': { + GET: { + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + }, + }, + }, + PATCH: { + admin: { + input: { + body: yupObject({ + description: yupString().optional(), + revoked: yupBoolean().optional().oneOf([true]), + }).defined(), + query: yupObject({}), + params: yupObject({ api_key_id: yupString().defined() }).optional(), + }, + output: { + statusCode: [200], + bodyType: 'json', + headers: yupObject({}).optional(), + body: yupObject({ + publishable_client_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + secret_server_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + super_secret_admin_key: yupObject({ + last_four: yupString().defined(), + }).optional(), + id: yupString().defined(), + description: yupString().defined(), + expires_at_millis: yupNumber().defined(), + manually_revoked_at_millis: yupNumber().optional(), + created_at_millis: yupNumber().defined(), + }).optional(), + }, + }, + }, + }, + '/contact-channels/[user_id]/[contact_channel_id]/send-verification-code': { + POST: { + client: { + input: { + body: yupObject({ callback_url: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).defined(), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + server: { + input: { + body: yupObject({ callback_url: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).defined(), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + admin: { + input: { + body: yupObject({ callback_url: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({ + user_id: yupString().defined(), + contact_channel_id: yupString().defined(), + }).defined(), + }, + output: { statusCode: [200], bodyType: 'success' }, + }, + }, + }, + '/auth/sessions/current/refresh': { + POST: { + client: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + server: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + admin: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ access_token: yupString().defined() }).defined(), + }, + }, + }, + }, + '/auth/password/reset/check-code': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + is_code_valid: yupBoolean().defined().oneOf([true]), + }).defined(), + }, + }, + }, + }, + '/auth/oauth/authorize/[provider_id]': { + GET: { + default: { + input: { + body: yupObject({}), + query: yupObject({ + type: yupString().optional().oneOf(['authenticate', 'link']), + token: yupString().optional(), + provider_scope: yupString().optional(), + error_redirect_url: yupString().optional(), + error_redirect_uri: yupString().optional(), + after_callback_redirect_url: yupString().optional(), + client_id: yupString().defined(), + client_secret: yupString().defined(), + redirect_uri: yupString().defined(), + scope: yupString().defined(), + state: yupString().defined(), + grant_type: yupString().defined().oneOf(['authorization_code']), + code_challenge: yupString().defined(), + code_challenge_method: yupString().defined(), + response_type: yupString().defined(), + }).defined(), + params: yupObject({ provider_id: yupString().defined() }).defined(), + }, + output: { statusCode: [302], bodyType: 'empty' }, + }, + }, + }, + '/auth/otp/sign-in/check-code': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + is_code_valid: yupBoolean().defined().oneOf([true]), + }).defined(), + }, + }, + }, + }, + '/auth/oauth/callback/[provider_id]': { + GET: { + default: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ provider_id: yupString().defined() }).defined(), + }, + output: { + statusCode: [307], + bodyType: 'json', + headers: yupMixed().defined(), + body: yupMixed().defined(), + }, + }, + }, + POST: { + default: { + input: { + body: yupObject({}), + query: yupObject({}), + params: yupObject({ provider_id: yupString().defined() }).defined(), + }, + output: { + statusCode: [307], + bodyType: 'json', + headers: yupMixed().defined(), + body: yupMixed().defined(), + }, + }, + }, + }, + '/integrations/neon/projects/transfer/initiate': { + POST: { + default: { + input: { + body: yupObject({ project_id: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ + confirmation_url: yupString().defined(), + }).defined(), + }, + }, + }, + }, + '/integrations/neon/projects/transfer/confirm': { + POST: { + default: { + input: { + body: yupObject({ code: yupString().defined() }).defined(), + query: yupObject({}), + params: yupObject({}), + }, + output: { + statusCode: [200], + bodyType: 'json', + body: yupObject({ project_id: yupString().defined() }).defined(), + }, + }, + }, + }, + '/integrations/neon/oauth/idp/[[...route]]': {}, + '/auth/oauth/connected-accounts/[provider_id]/access-token': { + POST: { + default: { + input: { + body: yupObject({ scope: yupString().optional() }).defined(), + query: yupObject({}), + params: yupObject({ provider_id: yupString().defined() }).defined(), + }, + output: { + statusCode: [], + bodyType: 'json', + body: yupMixed().defined(), + }, + }, + }, + }, +}; diff --git a/apps/backend/src/lib/glob.tsx b/apps/backend/src/lib/glob.tsx new file mode 100644 index 000000000..e306d56cc --- /dev/null +++ b/apps/backend/src/lib/glob.tsx @@ -0,0 +1,29 @@ +import { isSmartRouteHandler } from '@/route-handlers/smart-route-handler'; +import { HTTP_METHODS } from '@stackframe/stack-shared/dist/utils/http'; +import { typedKeys } from '@stackframe/stack-shared/dist/utils/objects'; +import { glob } from 'glob'; +import path from 'path'; + +export async function listEndpoints(basePath: string, onlySmartRouteHandlers: boolean, replaceBracketsWithCurlyBraces: boolean = false) { + const filePathPrefix = path.resolve(process.platform === "win32" ? `apps/src/app/${basePath}` : `src/app/${basePath}`); + const importPathPrefix = `@/app/${basePath}`; + const filePaths = [...await glob(filePathPrefix + "/**/route.{js,jsx,ts,tsx}")]; + + const endpoints = new Map(await Promise.all(filePaths.map(async (filePath) => { + if (!filePath.startsWith(filePathPrefix)) { + throw new Error(`Invalid file path: ${filePath}`); + } + const suffix = filePath.slice(filePathPrefix.length); + const midfix = suffix.slice(0, suffix.lastIndexOf("/route.")); + const urlPath = replaceBracketsWithCurlyBraces ? midfix.replaceAll("[", "{").replaceAll("]", "}") : midfix; + const importPath = `${importPathPrefix}${suffix}`; + const myModule = require(importPath); + const handlersByMethod = new Map( + typedKeys(HTTP_METHODS).map(method => [method, myModule[method]] as const) + .filter(([_, handler]) => isSmartRouteHandler(handler) || (!onlySmartRouteHandlers && handler)) + ); + return [urlPath, handlersByMethod] as const; + }))); + + return endpoints; +} diff --git a/apps/backend/src/lib/openapi.tsx b/apps/backend/src/lib/openapi.tsx index f4dfa54f7..ee2ce4f36 100644 --- a/apps/backend/src/lib/openapi.tsx +++ b/apps/backend/src/lib/openapi.tsx @@ -102,7 +102,7 @@ function isSchemaNumberDescription(value: yup.SchemaFieldDescription): value is return value.type === 'number'; } -function isMaybeRequestSchemaForAudience(requestDescribe: yup.SchemaObjectDescription, audience: 'client' | 'server' | 'admin') { +export function isMaybeRequestSchemaForAudience(requestDescribe: yup.SchemaObjectDescription, audience: 'client' | 'server' | 'admin') { const schemaAuth = requestDescribe.fields.auth; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- yup types are wrong and claim that fields always exist if (!schemaAuth) return true; diff --git a/apps/backend/src/route-handlers/migration-handler.tsx b/apps/backend/src/route-handlers/migration-handler.tsx new file mode 100644 index 000000000..959604995 --- /dev/null +++ b/apps/backend/src/route-handlers/migration-handler.tsx @@ -0,0 +1,435 @@ +import { yupValidate } from "@stackframe/stack-shared/dist/schema-fields"; +import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto"; +import { FilterUndefined, pick, typedEntries, typedFromEntries } from "@stackframe/stack-shared/dist/utils/objects"; +import { NextRequest, NextResponse } from "next/server"; +import * as yup from "yup"; +import { allowedMethods, createSmartRequest } from "./smart-request"; +import { createResponse } from "./smart-response"; + +type BodyType = 'json' | 'text' | 'binary' | 'success' | 'empty'; + +export type EndpointInputSchema< + Query extends yup.Schema, + Body extends yup.Schema +> = { + query: Query, + body: Body, +}; + +export type EndpointOutputSchema< + StatusCode extends number[], + T extends BodyType, + Body extends yup.Schema | undefined +> = { + statusCode: StatusCode, + bodyType: T, + body: Body, +}; + +export type EndpointsSchema = { + [url: string]: { + [method in (typeof allowedMethods)[number]]?: { + [overload: string]: { + input: EndpointInputSchema, + output: EndpointOutputSchema, + }, + } + }, +}; + +export type EndpointHandlers = { + [url: string]: { + [method in (typeof allowedMethods)[number]]?: { + [overload: string]: (req: ParsedRequest, options?: { params: Promise> }) => Promise, + } + }, +}; + +export type RawEndpointsHandlers = { + [url: string]: { + [method in (typeof allowedMethods)[number]]?: (req: NextRequest) => Promise + }, +} + +type ExtractInputOutputFromEndpointsSchema< + S extends EndpointsSchema, + U extends keyof S, + M extends typeof allowedMethods[number], + O extends keyof S[U][M], +> = NonNullable[O] + +export type ParsedRequestFromSchema< + S extends EndpointsSchema, + url extends keyof S, + method extends (typeof allowedMethods)[number], + overload extends keyof S[url][method] +> = ParsedRequest< + yup.InferType['input']['body']>, + yup.InferType['input']['query']> +> + +export type ParsedResponseFromSchema< + S extends EndpointsSchema, + url extends keyof S, + method extends (typeof allowedMethods)[number], + overload extends keyof S[url][method] +> = { + bodyType: ExtractInputOutputFromEndpointsSchema['output']['bodyType'], + statusCode: ExtractInputOutputFromEndpointsSchema['output']['statusCode'][number], + body: yup.InferType['output']['body']>, +} + +type EndpointHandlersFromSchema = { + [url in keyof S]: { + [method in (typeof allowedMethods)[number]]: { + [overload in keyof S[url][method]]: ( + req: ParsedRequestFromSchema, + options?: { params: Promise> } + ) => Promise> + } + } +} + +// given an object, return the object it self if at least one key exists, otherwise return undefined +type UndefinedIfNoKey = keyof T extends never ? undefined : T; +type FilterUndefinedAndEmpty = UndefinedIfNoKey>; + +export type TransformFn< + Old extends EndpointsSchema, + Handlers extends EndpointHandlers, + url extends keyof Old, + method extends (typeof allowedMethods)[number], + overload extends keyof Old[url][method] +> = (options: { + req: ParsedRequestFromSchema, + options?: { params: Promise> }, + newEndpointHandlers: Handlers, +}) => Promise> + +export type EndpointTransforms< + Old extends EndpointsSchema, + New extends EndpointsSchema, + Handlers extends EndpointHandlers, +> = FilterUndefinedAndEmpty<{ + [url in keyof Old]: FilterUndefinedAndEmpty<{ + [method in (typeof allowedMethods)[number]]: method extends keyof Old[url] ? + FilterUndefinedAndEmpty<{ + [overload in keyof Old[url][method]]: + url extends keyof New + ? Old[url][method][overload] extends New[url][method][overload] + ? undefined + : TransformFn + : TransformFn + }> + : undefined + }> +}> + +function urlMatch(url: string, nextPattern: string): Record | null { + const keys: string[] = []; + + const regexPattern = nextPattern + // match (name) + .replace(/\/\(.*?\)/g, '') + // match [...] + .replace(/\[\.\.\.\]/g, '.*') + // match [...name] + .replace(/\[\.\.\.\w+\]/g, (match) => { + const key = match.slice(1, -1); + keys.push(key); + return '(.*?)'; + }) + // match [name] + .replace(/\[\w+\]/g, (match) => { + const key = match.slice(1, -1); + keys.push(key); + return '([^/]+)'; + }); + + const regex = new RegExp(`^${regexPattern}$`); + const match = regex.exec(url); + + if (!match) return null; + + const result: Record = {}; + keys.forEach((key, index) => { + const value = match[index + 1]; + if (key.startsWith('...')) { + result[key.slice(3)] = value.split('/'); + } else { + result[key] = value; + } + }); + + return result; +} + +type ParsedRequest> = { + url: string, + method: typeof allowedMethods[number], + headers: Record, + body: Body, + query: Query, +}; +type ParsedResponse = { + statusCode: number, + bodyType: BodyType, + body?: any, +} + +async function convertRawToParsedRequest( + req: NextRequest, + schema: EndpointInputSchema, + options?: { params: Promise> } +): Promise, + yup.InferType +>> { + const bodyBuffer = await req.arrayBuffer(); + const smartRequest = await createSmartRequest(req, bodyBuffer, options); + const parsedRequest = pick(smartRequest, ["url", "method", "body", "headers", "query"]); + return { + ...parsedRequest, + body: await yupValidate(schema.body, parsedRequest.body), + query: await yupValidate(schema.query, parsedRequest.query), + }; +} + +async function convertParsedRequestToRaw(req: ParsedRequest>): Promise { + const url = new URL(req.url); + + for (const [key, value] of Object.entries(req.query)) { + if (value !== undefined) { + url.searchParams.set(key, value); + } + } + + return new NextRequest(url.toString(), { + body: JSON.stringify(req.body), + method: req.method, + headers: typedFromEntries(Object.entries(req.headers) + .map(([key, value]): [string, string | undefined] => [key, (value?.constructor === Array ? value.join(',') : value) as string | undefined]) + .filter(([_, value]) => value !== undefined)) as HeadersInit, + }); +} + +async function convertParsedResponseToRaw( + req: NextRequest, + response: ParsedResponse, + schema: yup.Schema +): Promise { + const requestId = generateSecureRandomString(80); + return await createResponse(req, requestId, response, schema); +} + +async function convertRawToParsedResponse< + Body extends yup.Schema, + StatusCode extends number[], + T extends BodyType, +>( + res: NextResponse, + schema: EndpointOutputSchema +): Promise<{ + statusCode: StatusCode[number], + bodyType: T, + body: yup.InferType, +}> { + // TODO validate schema + let contentType = res.headers.get("content-type"); + if (contentType) { + contentType = contentType.split(";")[0]; + } + + let result: ParsedResponse; + + switch (contentType) { + case "application/json": { + result = { + statusCode: res.status, + body: await res.json(), + bodyType: "json" as T, + }; + break; + } + case "text/plain": { + result = { + statusCode: res.status, + body: await res.text(), + bodyType: "text" as T, + }; + break; + } + case "binary": { + result = { + statusCode: res.status, + body: await res.arrayBuffer(), + bodyType: "binary" as T, + }; + break; + } + case "success": { + result = { + statusCode: res.status, + body: undefined, + bodyType: "success" as T, + }; + break; + } + case undefined: { + result = { + statusCode: res.status, + body: undefined, + bodyType: "empty" as T, + }; + break; + } + default: { + throw new Error(`Unsupported content type: ${contentType}`); + } + } + + return result as any; +} + +async function validateEndpointInput(input: EndpointInputSchema, req: ParsedRequest) { + try { + await yupValidate(input.body, req.body); + await yupValidate(input.query, req.query); + } catch (error) { + throw new Error(`Invalid request for ${req.method} ${req.url}\n\nOriginal error: ${error}`); + } +} + +async function validateEndpointOutput(output: EndpointOutputSchema, res: ParsedResponse) { + try { + await yupValidate(output.body, res.body); + if (!output.statusCode.includes(res.statusCode)) { + throw new Error(`Status code ${res.statusCode} not in ${output.statusCode.join(', ')}`); + } + if (output.bodyType !== res.bodyType) { + throw new Error(`Body type ${res.bodyType} not in ${output.bodyType}`); + } + return true; + } catch (error) { + throw new Error(`Invalid response for ${res.statusCode} ${res.bodyType}\n\nOriginal error: ${error}`); + } +} + + +export function createMigrationRoute(endpointHandlers: EndpointHandlers) { + return typedFromEntries(allowedMethods.map((method) => { + return [method, async (req: NextRequest) => { + for (const [url, endpointMethods] of Object.entries(endpointHandlers)) { + // TODO fix this + const match = urlMatch(new URL(req.url).pathname.replace('v2', 'v1'), url); + if (!match) { + return new NextResponse(null, { status: 404 }); + } else { + if (endpointMethods[method]) { + return NextResponse.json({ match, url: req.url, nextUrl: url }); + } else { + return new NextResponse(null, { status: 405 }); + } + } + } + }]; + })); +} + +function createEndpointHandlers< + S extends EndpointsSchema, +>( + oldEndpointsSchema: S, + getHandler: ( + url: string, + method: typeof allowedMethods[number], + overload: string, + endpointSchema: { + input: EndpointInputSchema, + output: EndpointOutputSchema, + } + ) => ( + req: ParsedRequest, + options?: { params: Promise> } + ) => Promise, +) { + const endpointHandlers = {}; + for (const [url, endpointMethods] of typedEntries(oldEndpointsSchema)) { + const urlHandlers = {}; + for (const [method, overloads] of typedEntries(endpointMethods)) { + if (!overloads) continue; + + const methodHandlers = {}; + for (const [overload, endpointSchema] of typedEntries(overloads)) { + (methodHandlers as any)[overload] = getHandler( + url as string, + method as typeof allowedMethods[number], + overload as string, + endpointSchema as { + input: EndpointInputSchema, + output: EndpointOutputSchema, + } + ); + } + (urlHandlers as any)[method] = methodHandlers; + } + (endpointHandlers as any)[url] = urlHandlers; + } + + return endpointHandlers as any; +} + +export function createMigrationEndpointHandlers< + Old extends EndpointsSchema, + New extends EndpointsSchema, + Handlers extends EndpointHandlers, +>( + oldEndpointsSchema: Old, + newEndpointsSchema: New, + newEndpointsHandlers: Handlers, + transforms: EndpointTransforms, +): EndpointHandlersFromSchema { + return createEndpointHandlers( + oldEndpointsSchema, + (url, method, overload, endpointSchema) => async (req: ParsedRequest): Promise => { + + let transformedRequest = req; + const transform = (transforms as any)[url]?.[method]?.[overload]; + if (transform) { + await validateEndpointInput(endpointSchema.input, transformedRequest); + const result = await transform({ req, newEndpointHandlers: newEndpointsHandlers }); + await validateEndpointOutput(endpointSchema.output, result); + return result; + } else { + const endpoint = (newEndpointsHandlers as any)[url]?.[method]; + + if (!endpoint) { + throw new Error(`No endpoint found for ${method.toString()} ${url.toString()}`); + } + + return endpoint[overload](transformedRequest); + } + } + ); +} + +export function createEndpointHandlersFromRawEndpoints< + H extends RawEndpointsHandlers, + S extends EndpointsSchema, + E extends EndpointHandlersFromSchema +>(rawEndpointHandlers: H, endpointsSchema: S): E { + return createEndpointHandlers( + endpointsSchema, + (url, method, overload, endpointSchema) => async (req: ParsedRequest): Promise => { + const endpoint = (rawEndpointHandlers as any)[url]?.[method]; + + if (!endpoint) { + throw new Error(`No endpoint found for ${method.toString()} ${url.toString()}`); + } + + const rawRequest = await convertParsedRequestToRaw(req); + const rawResponse = await endpoint(rawRequest); + return await convertRawToParsedResponse(rawResponse, endpointSchema.output); + } + ); +} diff --git a/apps/backend/src/route-handlers/smart-request.tsx b/apps/backend/src/route-handlers/smart-request.tsx index 4f211b4cf..7faafc14a 100644 --- a/apps/backend/src/route-handlers/smart-request.tsx +++ b/apps/backend/src/route-handlers/smart-request.tsx @@ -17,7 +17,7 @@ import { deindent } from "@stackframe/stack-shared/dist/utils/strings"; import { NextRequest } from "next/server"; import * as yup from "yup"; -const allowedMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] as const; +export const allowedMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] as const; export type SmartRequestAuth = { project: ProjectsCrud["Admin"]["Read"], @@ -94,7 +94,7 @@ async function validate(obj: SmartRequest, schema: yup.Schema, req: NextRe } -async function parseBody(req: NextRequest, bodyBuffer: ArrayBuffer): Promise { +export async function parseBody(req: NextRequest, bodyBuffer: ArrayBuffer): Promise { const contentType = req.headers.get("content-type")?.split(";")[0]; const getText = () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20a1e4b47..7be340785 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,6 +174,9 @@ importers: posthog-node: specifier: ^4.1.0 version: 4.1.0 + prettier: + specifier: ^3.4.2 + version: 3.4.2 react: specifier: ^19.0.0 version: 19.0.0 @@ -890,7 +893,7 @@ importers: version: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-email: specifier: 2.1.0 - version: 2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0) + version: 2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)) yup: specifier: ^1.4.0 version: 1.4.0 @@ -2321,12 +2324,33 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.19.1': + resolution: {integrity: sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.9.1': + resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@1.4.1': resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@floating-ui/core@1.6.2': - resolution: {integrity: sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==} + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.16.0': + resolution: {integrity: sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.5': + resolution: {integrity: sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.4': + resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@floating-ui/core@1.6.8': resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} @@ -2334,24 +2358,12 @@ packages: '@floating-ui/dom@1.6.12': resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==} - '@floating-ui/dom@1.6.5': - resolution: {integrity: sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==} - - '@floating-ui/react-dom@2.1.0': - resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - '@floating-ui/react-dom@2.1.2': resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/utils@0.2.2': - resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==} - '@floating-ui/utils@0.2.8': resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} @@ -2388,6 +2400,14 @@ packages: peerDependencies: react-hook-form: ^7.0.0 + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -2401,6 +2421,14 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} + '@img/sharp-darwin-arm64@0.33.4': resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} @@ -7122,6 +7150,10 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-utils@2.1.0: resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} engines: {node: '>=6'} @@ -7144,11 +7176,29 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.30.0: resolution: {integrity: sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true + eslint@9.16.0: + resolution: {integrity: sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7281,6 +7331,10 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -7304,6 +7358,10 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} @@ -7520,6 +7578,10 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -9339,6 +9401,11 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -12279,8 +12346,25 @@ snapshots: eslint: 8.30.0 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.4.1(eslint@9.16.0(jiti@1.21.6))': + dependencies: + eslint: 9.16.0(jiti@1.21.6) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.1': {} + '@eslint/config-array@0.19.1': + dependencies: + '@eslint/object-schema': 2.1.5 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.9.1': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/eslintrc@1.4.1': dependencies: ajv: 6.12.6 @@ -12295,9 +12379,27 @@ snapshots: transitivePeerDependencies: - supports-color - '@floating-ui/core@1.6.2': + '@eslint/eslintrc@3.2.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.16.0': {} + + '@eslint/object-schema@2.1.5': {} + + '@eslint/plugin-kit@0.2.4': dependencies: - '@floating-ui/utils': 0.2.2 + levn: 0.4.1 '@floating-ui/core@1.6.8': dependencies: @@ -12308,24 +12410,17 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/dom@1.6.5': - dependencies: - '@floating-ui/core': 1.6.2 - '@floating-ui/utils': 0.2.2 - - '@floating-ui/react-dom@2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/dom': 1.6.5 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react-dom@2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.6.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@floating-ui/utils@0.2.2': {} + '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.6.12 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) '@floating-ui/utils@0.2.8': {} @@ -12373,6 +12468,13 @@ snapshots: dependencies: react-hook-form: 7.53.1(react@18.3.1) + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -12385,6 +12487,10 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.1': {} + '@img/sharp-darwin-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.2 @@ -13975,7 +14081,7 @@ snapshots: '@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 - '@floating-ui/react-dom': 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.12)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.12)(react@18.3.1) @@ -14559,7 +14665,7 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@react-email/components@0.0.15(@types/react@18.3.12)(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1)': + '@react-email/components@0.0.15(@types/react@18.3.12)(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1)': dependencies: '@react-email/body': 0.0.7(react@18.3.1) '@react-email/button': 0.0.14(react@18.3.1) @@ -14574,7 +14680,7 @@ snapshots: '@react-email/html': 0.0.7(react@18.3.1) '@react-email/img': 0.0.7(react@18.3.1) '@react-email/link': 0.0.7(react@18.3.1) - '@react-email/markdown': 0.0.8(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1) + '@react-email/markdown': 0.0.8(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1) '@react-email/preview': 0.0.8(react@18.3.1) '@react-email/render': 0.0.12 '@react-email/row': 0.0.7(react@18.3.1) @@ -14656,9 +14762,9 @@ snapshots: dependencies: react: 18.3.1 - '@react-email/markdown@0.0.8(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1)': + '@react-email/markdown@0.0.8(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1)': dependencies: - md-to-react-email: 4.1.0(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1) + md-to-react-email: 4.1.0(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1) react: 18.3.1 transitivePeerDependencies: - react-email @@ -15359,7 +15465,7 @@ snapshots: '@types/acorn@4.0.6': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/aria-query@5.0.4': {} @@ -15480,7 +15586,7 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/estree@1.0.5': {} @@ -17474,14 +17580,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-config-prettier@9.0.0(eslint@8.30.0): + eslint-config-prettier@9.0.0(eslint@9.16.0(jiti@1.21.6)): dependencies: - eslint: 8.30.0 + eslint: 9.16.0(jiti@1.21.6) - eslint-config-turbo@1.10.12(eslint@8.30.0): + eslint-config-turbo@1.10.12(eslint@9.16.0(jiti@1.21.6)): dependencies: - eslint: 8.30.0 - eslint-plugin-turbo: 1.10.12(eslint@8.30.0) + eslint: 9.16.0(jiti@1.21.6) + eslint-plugin-turbo: 1.10.12(eslint@9.16.0(jiti@1.21.6)) eslint-import-resolver-node@0.3.9: dependencies: @@ -17696,10 +17802,10 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@1.10.12(eslint@8.30.0): + eslint-plugin-turbo@1.10.12(eslint@9.16.0(jiti@1.21.6)): dependencies: dotenv: 16.0.3 - eslint: 8.30.0 + eslint: 9.16.0(jiti@1.21.6) eslint-scope@5.1.1: dependencies: @@ -17711,6 +17817,11 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-scope@8.2.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-utils@2.1.0: dependencies: eslint-visitor-keys: 1.3.0 @@ -17726,6 +17837,8 @@ snapshots: eslint-visitor-keys@3.4.3: {} + eslint-visitor-keys@4.2.0: {} + eslint@8.30.0: dependencies: '@eslint/eslintrc': 1.4.1 @@ -17770,6 +17883,53 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@9.16.0(jiti@1.21.6): + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0(jiti@1.21.6)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.1 + '@eslint/core': 0.9.1 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.16.0 + '@eslint/plugin-kit': 0.2.4 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.5 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.6 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + espree@9.6.1: dependencies: acorn: 8.12.0 @@ -17792,7 +17952,7 @@ snapshots: estree-util-attach-comments@3.0.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-util-build-jsx@3.0.1: dependencies: @@ -17818,7 +17978,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 esutils@2.0.3: {} @@ -17902,6 +18062,10 @@ snapshots: dependencies: flat-cache: 3.2.0 + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -17928,6 +18092,11 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + flatted@3.3.1: {} follow-redirects@1.15.6: {} @@ -18129,7 +18298,7 @@ snapshots: glob@10.3.4: dependencies: - foreground-child: 3.2.1 + foreground-child: 3.3.0 jackspeak: 2.3.6 minimatch: 9.0.5 minipass: 7.1.2 @@ -18174,6 +18343,8 @@ snapshots: dependencies: type-fest: 0.20.2 + globals@14.0.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -18318,7 +18489,7 @@ snapshots: hast-util-to-estree@3.1.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -18339,7 +18510,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/hast': 3.0.4 '@types/unist': 3.0.2 comma-separated-tokens: 2.0.3 @@ -18734,7 +18905,7 @@ snapshots: is-reference@3.0.2: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 is-regex@1.1.4: dependencies: @@ -19123,11 +19294,11 @@ snapshots: '@types/minimatch': 3.0.5 minimatch: 3.1.2 - md-to-react-email@4.1.0(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1): + md-to-react-email@4.1.0(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1): dependencies: marked: 7.0.4 react: 18.3.1 - react-email: 2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0) + react-email: 2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)) mdast-util-find-and-replace@3.0.1: dependencies: @@ -19425,7 +19596,7 @@ snapshots: micromark-extension-mdx-expression@3.0.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.1 micromark-factory-space: 2.0.0 @@ -19437,7 +19608,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.0: dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.1 @@ -19453,7 +19624,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 micromark-util-character: 2.1.0 @@ -19489,7 +19660,7 @@ snapshots: micromark-factory-mdx-expression@2.0.1: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 devlop: 1.1.0 micromark-util-character: 2.1.0 micromark-util-events-to-acorn: 2.0.2 @@ -19553,7 +19724,7 @@ snapshots: micromark-util-events-to-acorn@2.0.2: dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/unist': 3.0.2 devlop: 1.1.0 estree-util-visit: 2.0.0 @@ -20296,7 +20467,7 @@ snapshots: periscopic@3.1.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 estree-walker: 3.0.3 is-reference: 3.0.2 @@ -20490,6 +20661,8 @@ snapshots: prettier@2.8.8: {} + prettier@3.4.2: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -20659,7 +20832,7 @@ snapshots: react: 19.0.0-rc-65a56d0e-20241020 scheduler: 0.25.0-rc-65a56d0e-20241020 - react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0): + react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)): dependencies: '@radix-ui/colors': 1.0.1 '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -20667,7 +20840,7 @@ snapshots: '@radix-ui/react-slot': 1.0.2(@types/react@18.3.12)(react@18.3.1) '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tooltip': 1.0.6(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-email/components': 0.0.15(@types/react@18.3.12)(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@8.30.0))(react@18.3.1) + '@react-email/components': 0.0.15(@types/react@18.3.12)(react-email@2.1.0(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.13)(eslint@9.16.0(jiti@1.21.6)))(react@18.3.1) '@react-email/render': 0.0.12 '@swc/core': 1.3.101(@swc/helpers@0.5.13) '@types/react': 18.3.12 @@ -20680,8 +20853,8 @@ snapshots: commander: 11.1.0 debounce: 2.0.0 esbuild: 0.19.11 - eslint-config-prettier: 9.0.0(eslint@8.30.0) - eslint-config-turbo: 1.10.12(eslint@8.30.0) + eslint-config-prettier: 9.0.0(eslint@9.16.0(jiti@1.21.6)) + eslint-config-turbo: 1.10.12(eslint@9.16.0(jiti@1.21.6)) framer-motion: 10.17.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) glob: 10.3.4 log-symbols: 4.1.0 @@ -22630,7 +22803,7 @@ snapshots: webpack@5.92.0(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.19.11): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 @@ -22638,7 +22811,7 @@ snapshots: acorn-import-attributes: 1.9.5(acorn@8.14.0) browserslist: 4.24.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.0 + enhanced-resolve: 5.17.1 es-module-lexer: 1.5.3 eslint-scope: 5.1.1 events: 3.3.0 @@ -22661,7 +22834,7 @@ snapshots: webpack@5.92.0(@swc/core@1.3.101)(esbuild@0.24.0): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 @@ -22669,7 +22842,7 @@ snapshots: acorn-import-attributes: 1.9.5(acorn@8.14.0) browserslist: 4.24.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.0 + enhanced-resolve: 5.17.1 es-module-lexer: 1.5.3 eslint-scope: 5.1.1 events: 3.3.0