fix(openapi): add operationIds to routes (#2107)

Co-authored-by: Maxwell <145994855+ping-maxwell@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Bereket Engida <86073083+Bekacru@users.noreply.github.com>
Co-authored-by: TheUntraceable <73362400+TheUntraceable@users.noreply.github.com>
Co-authored-by: Bereket Engida <Bekacru@gmail.com>
This commit is contained in:
Thomas Mol
2025-11-15 08:25:27 -08:00
committed by Bereket Engida
co-authored by Maxwell cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Bereket Engida TheUntraceable Bereket Engida
parent 7aa296e6cb
commit 4817a6e9a4
22 changed files with 194 additions and 127 deletions
@@ -19,6 +19,7 @@ export const listUserAccounts = createAuthEndpoint(
use: [sessionMiddleware],
metadata: {
openapi: {
operationId: "listUserAccounts",
description: "List all accounts linked to the user",
responses: {
"200": {
@@ -172,6 +173,7 @@ export const linkSocialAccount = createAuthEndpoint(
metadata: {
openapi: {
description: "Link a social account to the user",
operationId: "linkSocialAccount",
responses: {
"200": {
description: "Success",
@@ -21,6 +21,7 @@ export const callbackOAuth = createAuthEndpoint(
"/callback/:id",
{
method: ["GET", "POST"],
operationId: "handleOAuthCallback",
body: schema.optional(),
query: schema.optional(),
metadata: HIDE_METADATA,
@@ -69,6 +69,7 @@ export const sendVerificationEmail = createAuthEndpoint(
"/send-verification-email",
{
method: "POST",
operationId: "sendVerificationEmail",
body: z.object({
email: z.email().meta({
description: "The email to send the verification email to",
@@ -82,6 +83,7 @@ export const sendVerificationEmail = createAuthEndpoint(
}),
metadata: {
openapi: {
operationId: "sendVerificationEmail",
description: "Send a verification email to the user",
requestBody: {
content: {
@@ -191,6 +193,7 @@ export const verifyEmail = createAuthEndpoint(
"/verify-email",
{
method: "GET",
operationId: "verifyEmail",
query: z.object({
token: z.string().meta({
description: "The token to verify the email",
@@ -236,46 +239,7 @@ export const verifyEmail = createAuthEndpoint(
properties: {
user: {
type: "object",
properties: {
id: {
type: "string",
description: "User ID",
},
email: {
type: "string",
description: "User email",
},
name: {
type: "string",
description: "User name",
},
image: {
type: "string",
description: "User image URL",
},
emailVerified: {
type: "boolean",
description:
"Indicates if the user email is verified",
},
createdAt: {
type: "string",
description: "User creation date",
},
updatedAt: {
type: "string",
description: "User update date",
},
},
required: [
"id",
"email",
"name",
"image",
"emailVerified",
"createdAt",
"updatedAt",
],
$ref: "#/components/schemas/User",
},
status: {
type: "boolean",
@@ -35,6 +35,7 @@ export const requestPasswordReset = createAuthEndpoint(
"/request-password-reset",
{
method: "POST",
operationId: "forgetPassword",
body: z.object({
/**
* The email address of the user to send a password reset email to.
@@ -59,6 +60,7 @@ export const requestPasswordReset = createAuthEndpoint(
}),
metadata: {
openapi: {
operationId: "forgetPassword",
description: "Send a password reset email to the user",
responses: {
"200": {
@@ -139,6 +141,7 @@ export const requestPasswordResetCallback = createAuthEndpoint(
"/reset-password/:token",
{
method: "GET",
operationId: "forgetPasswordCallback",
query: z.object({
callbackURL: z.string().meta({
description: "The URL to redirect the user to reset their password",
@@ -147,7 +150,28 @@ export const requestPasswordResetCallback = createAuthEndpoint(
use: [originCheck((ctx) => ctx.query.callbackURL)],
metadata: {
openapi: {
operationId: "resetPasswordCallback",
description: "Redirects the user to the callback URL with the token",
parameters: [
{
name: "token",
in: "path",
required: true,
description: "The token to reset the password",
schema: {
type: "string",
},
},
{
name: "callbackURL",
in: "query",
required: true,
description: "The URL to redirect the user to reset their password",
schema: {
type: "string",
},
},
],
responses: {
"200": {
description: "Success",
@@ -194,6 +218,7 @@ export const resetPassword = createAuthEndpoint(
"/reset-password",
{
method: "POST",
operationId: "resetPassword",
query: z
.object({
token: z.string().optional(),
@@ -212,6 +237,7 @@ export const resetPassword = createAuthEndpoint(
}),
metadata: {
openapi: {
operationId: "resetPassword",
description: "Reset the password for a user",
responses: {
"200": {
@@ -31,10 +31,12 @@ export const getSession = <Option extends BetterAuthOptions>() =>
"/get-session",
{
method: "GET",
operationId: "getSession",
query: getSessionQuerySchema,
requireHeaders: true,
metadata: {
openapi: {
operationId: "getSession",
description: "Get the current session",
responses: {
"200": {
@@ -563,10 +565,12 @@ export const listSessions = <Option extends BetterAuthOptions>() =>
"/list-sessions",
{
method: "GET",
operationId: "listUserSessions",
use: [sessionMiddleware],
requireHeaders: true,
metadata: {
openapi: {
operationId: "listUserSessions",
description: "List all active sessions for the user",
responses: {
"200": {
+14 -71
View File
@@ -12,6 +12,7 @@ export const signInSocial = createAuthEndpoint(
"/sign-in/social",
{
method: "POST",
operationId: "socialSignIn",
body: z.object({
/**
* Callback URL to redirect to after the user
@@ -169,51 +170,20 @@ export const signInSocial = createAuthEndpoint(
type: "object",
description: "Session response when idToken is provided",
properties: {
token: {
type: "string",
},
user: {
type: "object",
$ref: "#/components/schemas/User",
},
url: {
type: "string",
},
redirect: {
type: "boolean",
enum: [false],
},
token: {
type: "string",
description: "Session token",
url: {
type: "null",
nullable: true,
},
user: {
type: "object",
properties: {
id: { type: "string" },
email: { type: "string" },
name: {
type: "string",
nullable: true,
},
image: {
type: "string",
nullable: true,
},
emailVerified: {
type: "boolean",
},
createdAt: {
type: "string",
format: "date-time",
},
updatedAt: {
type: "string",
format: "date-time",
},
},
required: [
"id",
"email",
"emailVerified",
"createdAt",
"updatedAt",
],
},
},
},
required: ["redirect", "token", "user"],
},
@@ -348,6 +318,7 @@ export const signInEmail = createAuthEndpoint(
"/sign-in/email",
{
method: "POST",
operationId: "signInEmail",
body: z.object({
/**
* Email of the user
@@ -387,6 +358,7 @@ export const signInEmail = createAuthEndpoint(
}),
metadata: {
openapi: {
operationId: "signInEmail",
description: "Sign in with email and password",
responses: {
"200": {
@@ -413,36 +385,7 @@ export const signInEmail = createAuthEndpoint(
},
user: {
type: "object",
properties: {
id: { type: "string" },
email: { type: "string" },
name: {
type: "string",
nullable: true,
},
image: {
type: "string",
nullable: true,
},
emailVerified: {
type: "boolean",
},
createdAt: {
type: "string",
format: "date-time",
},
updatedAt: {
type: "string",
format: "date-time",
},
},
required: [
"id",
"email",
"emailVerified",
"createdAt",
"updatedAt",
],
$ref: "#/components/schemas/User",
},
},
required: ["redirect", "token", "user"],
@@ -7,9 +7,11 @@ export const signOut = createAuthEndpoint(
"/sign-out",
{
method: "POST",
operationId: "signOut",
requireHeaders: true,
metadata: {
openapi: {
operationId: "signOut",
description: "Sign out the current user",
responses: {
"200": {
@@ -15,6 +15,7 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
"/sign-up/email",
{
method: "POST",
operationId: "signUpWithEmailAndPassword",
body: z.record(z.string(), z.any()),
metadata: {
$Infer: {
@@ -28,6 +29,7 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
} & AdditionalUserFieldsInput<O>,
},
openapi: {
operationId: "signUpWithEmailAndPassword",
description: "Sign up a user using email and password",
requestBody: {
content: {
@@ -20,6 +20,7 @@ export const updateUser = <O extends BetterAuthOptions>() =>
"/update-user",
{
method: "POST",
operationId: "updateUser",
body: z.record(
z.string().meta({
description: "Field name must be a string",
@@ -35,6 +36,7 @@ export const updateUser = <O extends BetterAuthOptions>() =>
},
},
openapi: {
operationId: "updateUser",
description: "Update the current user",
requestBody: {
content: {
@@ -63,9 +65,9 @@ export const updateUser = <O extends BetterAuthOptions>() =>
schema: {
type: "object",
properties: {
status: {
type: "boolean",
description: "Indicates if the update was successful",
user: {
type: "object",
$ref: "#/components/schemas/User",
},
},
},
@@ -129,6 +131,7 @@ export const changePassword = createAuthEndpoint(
"/change-password",
{
method: "POST",
operationId: "changePassword",
body: z.object({
/**
* The new password to set
@@ -156,6 +159,7 @@ export const changePassword = createAuthEndpoint(
use: [sensitiveSessionMiddleware],
metadata: {
openapi: {
operationId: "changePassword",
description: "Change the password of the user",
responses: {
"200": {
@@ -406,7 +410,33 @@ export const deleteUser = createAuthEndpoint(
}),
metadata: {
openapi: {
operationId: "deleteUser",
description: "Delete the user",
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
callbackURL: {
type: "string",
description:
"The callback URL to redirect to after the user is deleted",
},
password: {
type: "string",
description:
"The user's password. Required if session is not fresh",
},
token: {
type: "string",
description: "The deletion verification token",
},
},
},
},
},
},
responses: {
"200": {
description: "User deletion processed successfully",
@@ -657,6 +687,7 @@ export const changeEmail = createAuthEndpoint(
use: [sensitiveSessionMiddleware],
metadata: {
openapi: {
operationId: "changeEmail",
responses: {
"200": {
description: "Email change request processed successfully",
@@ -665,6 +696,10 @@ export const changeEmail = createAuthEndpoint(
schema: {
type: "object",
properties: {
user: {
type: "object",
$ref: "#/components/schemas/User",
},
status: {
type: "boolean",
description: "Indicates if the request was successful",
@@ -217,7 +217,7 @@ export const admin = <O extends AdminOptions>(options?: O | undefined) => {
use: [adminMiddleware],
metadata: {
openapi: {
operationId: "setRole",
operationId: "setUserRole",
summary: "Set the role of a user",
description: "Set the role of a user",
responses: {
@@ -195,7 +195,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
}),
metadata: {
openapi: {
description: "Send verification OTP",
operationId: "sendEmailVerificationOTP",
description: "Send a verification OTP to an email",
responses: {
200: {
description: "Success",
@@ -329,7 +330,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
metadata: {
SERVER_ONLY: true,
openapi: {
description: "Create verification OTP",
operationId: "createEmailVerificationOTP",
description: "Create a verification OTP for an email",
responses: {
200: {
description: "Success",
@@ -387,7 +389,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
metadata: {
SERVER_ONLY: true,
openapi: {
description: "Get verification OTP",
operationId: "getEmailVerificationOTP",
description: "Get a verification OTP for an email",
responses: {
"200": {
description:
@@ -484,7 +487,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
}),
metadata: {
openapi: {
description: "Check if a verification OTP is valid",
operationId: "verifyEmailWithOTP",
description: "Verify an email with an OTP",
responses: {
200: {
description: "Success",
@@ -786,7 +790,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
}),
metadata: {
openapi: {
description: "Sign in with OTP",
operationId: "signInWithEmailOTP",
description: "Sign in with email and OTP",
responses: {
200: {
description: "Success",
@@ -942,7 +947,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
}),
metadata: {
openapi: {
description: "Send a password reset OTP to the user",
operationId: "forgetPasswordWithEmailOTP",
description: "Forget password with email and OTP",
responses: {
200: {
description: "Success",
@@ -1027,7 +1033,8 @@ export const emailOTP = (options: EmailOTPOptions) => {
}),
metadata: {
openapi: {
description: "Reset user password with OTP",
operationId: "resetPasswordWithEmailOTP",
description: "Reset password with email and OTP",
responses: {
200: {
description: "Success",
@@ -44,6 +44,7 @@ export const jwt = (options?: JwtOptions | undefined) => {
method: "GET",
metadata: {
openapi: {
operationId: "getJSONWebKeySet",
description: "Get the JSON Web Key Set",
responses: {
"200": {
@@ -172,6 +173,7 @@ export const jwt = (options?: JwtOptions | undefined) => {
use: [sessionMiddleware],
metadata: {
openapi: {
operationId: "getJSONWebToken",
description: "Get a JWT token",
responses: {
200: {
@@ -147,6 +147,7 @@ export const magicLink = (options: MagicLinkopts) => {
}),
metadata: {
openapi: {
operationId: "signInWithMagicLink",
description: "Sign in with magic link",
responses: {
200: {
@@ -287,6 +288,7 @@ export const magicLink = (options: MagicLinkopts) => {
requireHeaders: true,
metadata: {
openapi: {
operationId: "verifyMagicLink",
description: "Verify magic link",
responses: {
200: {
@@ -89,6 +89,7 @@ export const oAuthProxy = (opts?: OAuthProxyOptions | undefined) => {
"/oauth-proxy-callback",
{
method: "GET",
operationId: "oauthProxyCallback",
query: z.object({
callbackURL: z.string().meta({
description: "The URL to redirect to after the proxy",
@@ -100,6 +101,7 @@ export const oAuthProxy = (opts?: OAuthProxyOptions | undefined) => {
use: [originCheck((ctx) => ctx.query.callbackURL)],
metadata: {
openapi: {
operationId: "oauthProxyCallback",
description: "OAuth Proxy Callback",
parameters: [
{
@@ -284,6 +284,7 @@ export const oidcProvider = (options: OIDCOptions) => {
"/.well-known/openid-configuration",
{
method: "GET",
operationId: "getOpenIdConfig",
metadata: {
isAction: false,
},
@@ -297,6 +298,7 @@ export const oidcProvider = (options: OIDCOptions) => {
"/oauth2/authorize",
{
method: "GET",
operationId: "oauth2Authorize",
query: z.record(z.string(), z.any()),
metadata: {
openapi: {
@@ -327,6 +329,7 @@ export const oidcProvider = (options: OIDCOptions) => {
"/oauth2/consent",
{
method: "POST",
operationId: "oauth2Consent",
body: z.object({
accept: z.boolean(),
consent_code: z.string().optional().nullish(),
@@ -480,6 +483,7 @@ export const oidcProvider = (options: OIDCOptions) => {
"/oauth2/token",
{
method: "POST",
operationId: "oauth2Token",
body: z.record(z.any(), z.any()),
metadata: {
isAction: false,
@@ -908,7 +912,8 @@ export const oidcProvider = (options: OIDCOptions) => {
"/oauth2/userinfo",
{
method: "GET",
operationId: "oauth2Userinfo",
use: [sessionMiddleware],
metadata: {
isAction: false,
openapi: {
@@ -90,6 +90,7 @@ export type FieldSchema = {
| (DBFieldAttributeConfig["defaultValue"] | "Generated at runtime")
| undefined;
readOnly?: boolean | undefined;
format?: string;
};
export type OpenAPIModelSchema = {
@@ -346,7 +347,13 @@ export async function generator(ctx: AuthContext, options: BetterAuthOptions) {
plugins: [],
});
const tables = getAuthTables(options);
const tables = getAuthTables({
...options,
session: {
...options.session,
storeSessionInDatabase: true, // Forcing this to true to return the session table schema
},
});
const models = Object.entries(tables).reduce<
Record<string, OpenAPIModelSchema>
>((acc, [key, value]) => {
@@ -364,10 +371,16 @@ export async function generator(ctx: AuthContext, options: BetterAuthOptions) {
}
});
Object.entries(properties).forEach(([key, prop]) => {
const field = value.fields[key];
if (field && field.type === "date" && prop.type === "string") {
prop.format = "date-time";
}
});
acc[modelName] = {
type: "object",
properties,
...(required.length > 0 ? { required } : {}),
required,
};
return acc;
}, {});
@@ -121,7 +121,8 @@ export const createInvitation = <O extends OrganizationOptions>(option: O) => {
InferAdditionalFieldsFromPluginOptions<"invitation", O, false>,
},
openapi: {
description: "Invite a user to an organization",
operationId: "createOrganizationInvitation",
description: "Create an invitation to an organization",
responses: {
"200": {
description: "Success",
@@ -781,6 +782,7 @@ export const cancelInvitation = <O extends OrganizationOptions>(options: O) =>
}),
use: [orgMiddleware, orgSessionMiddleware],
openapi: {
operationId: "cancelOrganizationInvitation",
description: "Cancel an invitation to an organization",
responses: {
"200": {
@@ -69,6 +69,10 @@ export const addMember = <O extends OrganizationOptions>(option: O) => {
: {}) &
InferAdditionalFieldsFromPluginOptions<"member", O>,
},
openapi: {
operationId: "addOrganizationMember",
description: "Add a member to an organization",
},
},
},
async (ctx) => {
@@ -448,6 +452,7 @@ export const updateMemberRole = <O extends OrganizationOptions>(option: O) =>
},
},
openapi: {
operationId: "updateOrganizationMemberRole",
description: "Update the role of a member in an organization",
responses: {
"200": {
@@ -682,6 +682,7 @@ export const getFullOrganization = <O extends OrganizationOptions>(
use: [orgMiddleware, orgSessionMiddleware],
metadata: {
openapi: {
operationId: "getOrganization",
description: "Get the full organization",
responses: {
"200": {
@@ -777,6 +778,7 @@ export const setActiveOrganization = <O extends OrganizationOptions>(
use: [orgSessionMiddleware, orgMiddleware],
metadata: {
openapi: {
operationId: "setActiveOrganization",
description: "Set the active organization",
responses: {
"200": {
+4
View File
@@ -62,6 +62,7 @@ export const passkey = (options?: PasskeyOptions | undefined) => {
metadata: {
client: false,
openapi: {
operationId: "generatePasskeyRegistrationOptions",
description: "Generate registration options for a new passkey",
responses: {
200: {
@@ -254,6 +255,7 @@ export const passkey = (options?: PasskeyOptions | undefined) => {
method: "POST",
metadata: {
openapi: {
operationId: "passkeyGenerateAuthenticateOptions",
description: "Generate authentication options for a passkey",
responses: {
200: {
@@ -416,6 +418,7 @@ export const passkey = (options?: PasskeyOptions | undefined) => {
use: [freshSessionMiddleware],
metadata: {
openapi: {
operationId: "passkeyVerifyRegistration",
description: "Verify registration of a new passkey",
responses: {
200: {
@@ -540,6 +543,7 @@ export const passkey = (options?: PasskeyOptions | undefined) => {
}),
metadata: {
openapi: {
operationId: "passkeyVerifyAuthentication",
description: "Verify authentication of a passkey",
responses: {
200: {
+6
View File
@@ -63,6 +63,7 @@ export const spMetadata = () => {
}),
metadata: {
openapi: {
operationId: "getSSOServiceProviderMetadata",
summary: "Get Service Provider metadata",
description: "Returns the SAML metadata for the Service Provider",
responses: {
@@ -337,6 +338,7 @@ export const registerSSOProvider = (options?: SSOOptions) => {
use: [sessionMiddleware],
metadata: {
openapi: {
operationId: "registerSSOProvider",
summary: "Register an OIDC provider",
description:
"This endpoint is used to register an OIDC provider. This is used to configure the provider and link it to an organization",
@@ -726,6 +728,7 @@ export const signInSSO = (options?: SSOOptions) => {
}),
metadata: {
openapi: {
operationId: "signInWithSSO",
summary: "Sign in with SSO provider",
description:
"This endpoint is used to sign in with an SSO provider. It redirects to the provider's authorization URL",
@@ -1014,6 +1017,7 @@ export const callbackSSO = (options?: SSOOptions) => {
metadata: {
isAction: false,
openapi: {
operationId: "handleSSOCallback",
summary: "Callback URL for SSO provider",
description:
"This endpoint is used as the callback URL for SSO providers. It handles the authorization code and exchanges it for an access token",
@@ -1362,6 +1366,7 @@ export const callbackSSOSAML = (options?: SSOOptions) => {
metadata: {
isAction: false,
openapi: {
operationId: "handleSAMLCallback",
summary: "Callback URL for SAML provider",
description:
"This endpoint is used as the callback URL for SAML providers.",
@@ -1695,6 +1700,7 @@ export const acsEndpoint = (options?: SSOOptions) => {
metadata: {
isAction: false,
openapi: {
operationId: "handleSAMLAssertionConsumerService",
summary: "SAML Assertion Consumer Service",
description:
"Handles SAML responses from IdP after successful authentication",
+39 -1
View File
@@ -237,6 +237,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
})
.default(false),
}),
metadata: {
openapi: {
operationId: "upgradeSubscription",
},
},
use: [
sessionMiddleware,
originCheck((c) => {
@@ -635,6 +640,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
{
method: "GET",
query: z.record(z.string(), z.any()).optional(),
metadata: {
openapi: {
operationId: "cancelSubscriptionCallback",
},
},
use: [originCheck((ctx) => ctx.query.callbackURL)],
},
async (ctx) => {
@@ -744,9 +754,14 @@ export const stripe = <O extends StripeOptions>(options: O) => {
.optional(),
returnUrl: z.string().meta({
description:
'URL to take customers to when they click on the billing portals link to return to your website. Eg: "https://example.com/dashboard"',
'URL to take customers to when they click on the billing portal\'s link to return to your website. Eg: "/account"',
}),
}),
metadata: {
openapi: {
operationId: "cancelSubscription",
},
},
use: [
sessionMiddleware,
originCheck((ctx) => ctx.body.returnUrl),
@@ -887,6 +902,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
})
.optional(),
}),
metadata: {
openapi: {
operationId: "restoreSubscription",
},
},
use: [sessionMiddleware, referenceMiddleware("restore-subscription")],
},
async (ctx) => {
@@ -1015,6 +1035,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
.optional(),
}),
),
metadata: {
openapi: {
operationId: "listActiveSubscriptions",
},
},
use: [sessionMiddleware, referenceMiddleware("list-subscription")],
},
async (ctx) => {
@@ -1056,6 +1081,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
{
method: "GET",
query: z.record(z.string(), z.any()).optional(),
metadata: {
openapi: {
operationId: "handleSubscriptionSuccess",
},
},
use: [originCheck((ctx) => ctx.query.callbackURL)],
},
async (ctx) => {
@@ -1166,6 +1196,11 @@ export const stripe = <O extends StripeOptions>(options: O) => {
referenceId: z.string().optional(),
returnUrl: z.string().default("/"),
}),
metadata: {
openapi: {
operationId: "createBillingPortal",
},
},
use: [
sessionMiddleware,
originCheck((ctx) => ctx.body.returnUrl),
@@ -1236,6 +1271,9 @@ export const stripe = <O extends StripeOptions>(options: O) => {
method: "POST",
metadata: {
isAction: false,
openapi: {
operationId: "handleStripeWebhook",
},
},
cloneRequest: true,
//don't parse the body