mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-11 04:19:31 +00:00
feat: open api docs plugin
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
|||||||
twoFactor,
|
twoFactor,
|
||||||
oneTap,
|
oneTap,
|
||||||
oAuthProxy,
|
oAuthProxy,
|
||||||
createAuthEndpoint,
|
openAPI,
|
||||||
} from "better-auth/plugins";
|
} from "better-auth/plugins";
|
||||||
import { reactInvitationEmail } from "./email/invitation";
|
import { reactInvitationEmail } from "./email/invitation";
|
||||||
import { LibsqlDialect } from "@libsql/kysely-libsql";
|
import { LibsqlDialect } from "@libsql/kysely-libsql";
|
||||||
@@ -18,7 +18,6 @@ import { MysqlDialect } from "kysely";
|
|||||||
import { createPool } from "mysql2/promise";
|
import { createPool } from "mysql2/promise";
|
||||||
import { nextCookies } from "better-auth/next-js";
|
import { nextCookies } from "better-auth/next-js";
|
||||||
import { customSession } from "./auth/plugins/custom-session";
|
import { customSession } from "./auth/plugins/custom-session";
|
||||||
import { openAPI } from "@better-auth/open-api";
|
|
||||||
|
|
||||||
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
|
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
|
||||||
const to = process.env.TEST_EMAIL || "";
|
const to = process.env.TEST_EMAIL || "";
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@better-auth/open-api": "workspace:1.0.0-canary.12",
|
|
||||||
"@better-fetch/fetch": "1.1.12",
|
"@better-fetch/fetch": "1.1.12",
|
||||||
"@hookform/resolvers": "^3.9.0",
|
"@hookform/resolvers": "^3.9.0",
|
||||||
"@libsql/client": "^0.12.0",
|
"@libsql/client": "^0.12.0",
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { ForkButton } from "@/components/fork-button";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||||
import { AutoTypeTable } from "fumadocs-typescript/ui";
|
import { AutoTypeTable } from "fumadocs-typescript/ui";
|
||||||
import { openapi } from '@/app/source';
|
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page({
|
||||||
params,
|
params,
|
||||||
@@ -74,11 +73,9 @@ export default async function Page({
|
|||||||
Features,
|
Features,
|
||||||
ForkButton,
|
ForkButton,
|
||||||
DatabaseTable,
|
DatabaseTable,
|
||||||
APIPage: openapi.APIPage,
|
|
||||||
iframe: (props) => (
|
iframe: (props) => (
|
||||||
<iframe {...props} className="w-full h-[500px]" />
|
<iframe {...props} className="w-full h-[500px]" />
|
||||||
),
|
),
|
||||||
APIPage: openapi.APIPage,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DocsBody>
|
</DocsBody>
|
||||||
@@ -87,48 +84,48 @@ export default async function Page({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
// const res = source.getPages().map((page) => ({
|
const res = source.getPages().map((page) => ({
|
||||||
// slug: page.slugs,
|
slug: page.slugs,
|
||||||
// }));
|
}));
|
||||||
return source.generateParams();
|
return source.generateParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
// export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
// params,
|
params,
|
||||||
// }: { params: Promise<{ slug?: string[] }> }) {
|
}: { params: Promise<{ slug?: string[] }> }) {
|
||||||
// const { slug } = await params;
|
const { slug } = await params;
|
||||||
// const page = source.getPage(slug);
|
const page = source.getPage(slug);
|
||||||
// if (page == null) notFound();
|
if (page == null) notFound();
|
||||||
// const baseUrl = process.env.NEXT_PUBLIC_URL || process.env.VERCEL_URL;
|
const baseUrl = process.env.NEXT_PUBLIC_URL || process.env.VERCEL_URL;
|
||||||
// const url = new URL(`${baseUrl}/api/og`);
|
const url = new URL(`${baseUrl}/api/og`);
|
||||||
// const { title, description } = page.data;
|
const { title, description } = page.data;
|
||||||
// const pageSlug = page.file.path;
|
const pageSlug = page.file.path;
|
||||||
// url.searchParams.set("type", "Documentation");
|
url.searchParams.set("type", "Documentation");
|
||||||
// url.searchParams.set("mode", "dark");
|
url.searchParams.set("mode", "dark");
|
||||||
// url.searchParams.set("heading", `${title}`);
|
url.searchParams.set("heading", `${title}`);
|
||||||
|
|
||||||
// return {
|
return {
|
||||||
// title,
|
title,
|
||||||
// description,
|
description,
|
||||||
// openGraph: {
|
openGraph: {
|
||||||
// title,
|
title,
|
||||||
// description,
|
description,
|
||||||
// type: "website",
|
type: "website",
|
||||||
// url: absoluteUrl(`docs/${pageSlug}`),
|
url: absoluteUrl(`docs/${pageSlug}`),
|
||||||
// images: [
|
images: [
|
||||||
// {
|
{
|
||||||
// url: url.toString(),
|
url: url.toString(),
|
||||||
// width: 1200,
|
width: 1200,
|
||||||
// height: 630,
|
height: 630,
|
||||||
// alt: title,
|
alt: title,
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// },
|
},
|
||||||
// twitter: {
|
twitter: {
|
||||||
// card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
// title,
|
title,
|
||||||
// description,
|
description,
|
||||||
// images: [url.toString()],
|
images: [url.toString()],
|
||||||
// },
|
},
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ import { createOpenAPI } from "fumadocs-openapi/server";
|
|||||||
export const source = loader({
|
export const source = loader({
|
||||||
baseUrl: "/docs",
|
baseUrl: "/docs",
|
||||||
source: createMDXSource(docs, meta),
|
source: createMDXSource(docs, meta),
|
||||||
pageTree: {
|
|
||||||
attachFile,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const changelog = loader({
|
export const changelog = loader({
|
||||||
|
|||||||
@@ -877,6 +877,13 @@ export const contents: Content[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Open API",
|
||||||
|
href: "/docs/plugins/open-api",
|
||||||
|
icon: ()=>(
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.1em" height="1.1em" viewBox="0 0 32 32"><path fill="currentColor" d="M16 0C7.177 0 0 7.177 0 16s7.177 16 16 16s16-7.177 16-16S24.823 0 16 0m0 1.527c7.995 0 14.473 6.479 14.473 14.473S23.994 30.473 16 30.473S1.527 23.994 1.527 16S8.006 1.527 16 1.527m-4.839 6.296c-.188-.005-.375 0-.568.005c-1.307.079-2.093.693-2.312 1.964c-.151.891-.125 1.796-.188 2.692a9 9 0 0 1-.156 1.38c-.177.813-.525 1.068-1.353 1.109q-.167.018-.324.057v1.948c1.5.073 1.704.605 1.823 2.172c.048.573-.015 1.147.021 1.719q.042.816.208 1.6c.344 1.432 1.745 1.911 3.433 1.624V22.38c-.272 0-.511.005-.74 0c-.579-.016-.792-.161-.844-.713c-.079-.713-.057-1.437-.099-2.156c-.089-1.339-.235-2.651-1.541-3.5c.672-.495 1.161-1.084 1.312-1.865c.109-.547.177-1.099.219-1.651s-.025-1.12.021-1.667c.077-.885.135-1.249 1.197-1.213c.161 0 .317-.021.495-.036V7.834c-.213 0-.411-.005-.604-.011m10.126.016a5.4 5.4 0 0 0-1.089.079v1.697c.329 0 .584 0 .833.005c.439.005.772.177.813.661c.041.443.041.891.083 1.339c.089.896.136 1.796.292 2.677c.136.724.636 1.265 1.255 1.713c-1.088.729-1.411 1.776-1.463 2.953c-.032.801-.052 1.615-.093 2.427c-.037.74-.297.979-1.043.995c-.208.011-.411.027-.64.041v1.74c.432 0 .833.027 1.235 0c1.239-.073 1.995-.677 2.239-1.885a15 15 0 0 0 .183-2.005c.041-.615.036-1.235.099-1.844c.093-.953.532-1.349 1.484-1.411q.133-.018.267-.057v-1.953c-.161-.021-.271-.037-.391-.041c-.713-.032-1.068-.272-1.251-.948a6.6 6.6 0 0 1-.197-1.324c-.052-.823-.047-1.656-.099-2.479c-.109-1.588-1.063-2.339-2.516-2.38zm-9.188 7.036c-1.432 0-1.536 2.109-.115 2.245h.079a1.103 1.103 0 0 0 1.167-1.037v-.061a1.13 1.13 0 0 0-1.104-1.147zm3.88 0a1.083 1.083 0 0 0-1.115 1.043c0 .036 0 .067.005.104c0 .672.459 1.099 1.147 1.099c.677 0 1.104-.443 1.104-1.136c-.005-.672-.459-1.115-1.141-1.109zm3.948 0a1.15 1.15 0 0 0-1.167 1.115c0 .625.505 1.131 1.136 1.131h.011c.567.099 1.135-.448 1.172-1.104c.031-.609-.521-1.141-1.152-1.141z"></path></svg>
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "JWT",
|
title: "JWT",
|
||||||
icon: () => (
|
icon: () => (
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Link social account
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /link-social
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/link-social","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: List all accounts
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /list-accounts
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/list-accounts","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Callback
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /callback/:id
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/callback/:id","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Send verification email
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /send-verification-email
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/send-verification-email","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Verify email
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /verify-email
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/verify-email","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Forget password
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /forget-password
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/forget-password","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Reset password with token
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /reset-password/:token
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/reset-password/:token","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Reset password
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /reset-password
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/reset-password","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Get current session
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /get-session
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/get-session","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: List all sessions
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: GET
|
|
||||||
route: /list-sessions
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/list-sessions","method":"get"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Revoke other sessions
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /revoke-other-sessions
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/revoke-other-sessions","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Revoke a session
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /revoke-session
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/revoke-session","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Revoke all sessions
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /revoke-sessions
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/revoke-sessions","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Sign in with email
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /sign-in/email
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/sign-in/email","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Sign in with social account
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /sign-in/social
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/sign-in/social","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Sign out
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /sign-out
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/sign-out","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Sign up with email
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /sign-up/email
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/sign-up/email","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Change email
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /change-email
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/change-email","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Change password
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /change-password
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/change-password","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Delete user
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /delete-user
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/delete-user","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Set password
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /set-password
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/set-password","method":"post"}]} hasHead={false} />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Update user
|
|
||||||
full: true
|
|
||||||
_openapi:
|
|
||||||
method: POST
|
|
||||||
route: /update-user
|
|
||||||
toc: []
|
|
||||||
structuredData:
|
|
||||||
headings: []
|
|
||||||
contents: []
|
|
||||||
---
|
|
||||||
|
|
||||||
<APIPage document={"./open-api.json"} operations={[{"path":"/update-user","method":"post"}]} hasHead={false} />
|
|
||||||
38
docs/content/docs/plugins/open-api.mdx
Normal file
38
docs/content/docs/plugins/open-api.mdx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
title: Open API
|
||||||
|
description: Open API reference for Better Auth.
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a plugin that provides an Open API reference for Better Auth. It shows all endpoints added by plugins and the core. It also provides a way to test the endpoints. It uses [Scalar](https://scalar.com/) to display the Open API reference.
|
||||||
|
|
||||||
|
|
||||||
|
<Callout>
|
||||||
|
This plugin is still in the early stages of development. We are working on adding more features to it and filling in the gaps.
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
<Step>
|
||||||
|
### Add the plugin to your **auth** config
|
||||||
|
```ts title="auth.ts"
|
||||||
|
import { betterAuth } from "better-auth"
|
||||||
|
import { openAPI } from "better-auth/plugins"
|
||||||
|
|
||||||
|
export const auth = betterAuth({
|
||||||
|
plugins: [ // [!code highlight]
|
||||||
|
openAPI(), // [!code highlight]
|
||||||
|
] // [!code highlight]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
</Step>
|
||||||
|
<Step>
|
||||||
|
### Navigate to `/api/auth/reference` to view the Open API reference
|
||||||
|
|
||||||
|
Each plugin endpoints are grouped by the plugin name. The core endpoints are grouped under the `Default` group. And Model schemas are grouped under the `Models` group.
|
||||||
|
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
7266
docs/openapi.json
7266
docs/openapi.json
File diff suppressed because it is too large
Load Diff
1341
docs/openapi.yml
1341
docs/openapi.yml
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"build:docs": "node ./scripts/generate-docs.mjs",
|
"build:docs": "node ./scripts/generate-docs.mjs",
|
||||||
"build:docs": "node ./scripts/generate-docs.mjs",
|
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"postinstall": "fumadocs-mdx"
|
"postinstall": "fumadocs-mdx"
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
docs/public/open-api-reference.png
Normal file
BIN
docs/public/open-api-reference.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 415 KiB |
File diff suppressed because it is too large
Load Diff
@@ -405,7 +405,7 @@
|
|||||||
"@noble/hashes": "^1.5.0",
|
"@noble/hashes": "^1.5.0",
|
||||||
"@simplewebauthn/browser": "^10.0.0",
|
"@simplewebauthn/browser": "^10.0.0",
|
||||||
"@simplewebauthn/server": "^10.0.1",
|
"@simplewebauthn/server": "^10.0.1",
|
||||||
"better-call": "0.3.1",
|
"better-call": "0.3.2",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"jose": "^5.9.4",
|
"jose": "^5.9.4",
|
||||||
|
|||||||
@@ -10,6 +10,34 @@ export const listUserAccounts = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "List all accounts linked to the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
provider: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const session = c.context.session;
|
const session = c.context.session;
|
||||||
@@ -45,13 +73,45 @@ export const linkSocialAccount = createAuthEndpoint(
|
|||||||
/**
|
/**
|
||||||
* Callback URL to redirect to after the user has signed in.
|
* Callback URL to redirect to after the user has signed in.
|
||||||
*/
|
*/
|
||||||
callbackURL: z.string().optional(),
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description: "The URL to redirect to after the user has signed in",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* OAuth2 provider to use`
|
* OAuth2 provider to use`
|
||||||
*/
|
*/
|
||||||
provider: z.enum(socialProviderList),
|
provider: z.enum(socialProviderList, {
|
||||||
|
description: "The OAuth2 provider to use",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Link a social account to the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
url: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
redirect: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["url", "redirect"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const session = c.context.session;
|
const session = c.context.session;
|
||||||
|
|||||||
@@ -38,13 +38,68 @@ export const sendVerificationEmail = createAuthEndpoint(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
query: z
|
query: z
|
||||||
.object({
|
.object({
|
||||||
currentURL: z.string().optional(),
|
currentURL: z
|
||||||
|
.string({
|
||||||
|
description: "The URL to use for email verification callback",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
email: z.string().email(),
|
email: z
|
||||||
callbackURL: z.string().optional(),
|
.string({
|
||||||
|
description: "The email to send the verification email to",
|
||||||
|
})
|
||||||
|
.email(),
|
||||||
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description: "The URL to use for email verification callback",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Send a verification email to the user",
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: "string",
|
||||||
|
description: "The email to send the verification email to",
|
||||||
|
},
|
||||||
|
callbackURL: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The URL to use for email verification callback",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["email"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
|
if (!ctx.context.options.emailVerification?.sendVerificationEmail) {
|
||||||
@@ -85,9 +140,41 @@ export const verifyEmail = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: z.object({
|
query: z.object({
|
||||||
token: z.string(),
|
token: z.string({
|
||||||
callbackURL: z.string().optional(),
|
description: "The token to verify the email",
|
||||||
|
}),
|
||||||
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description: "The URL to redirect to after email verification",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Verify the email of the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["user", "status"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
function redirectOnError(error: string) {
|
function redirectOnError(error: string) {
|
||||||
|
|||||||
@@ -87,7 +87,24 @@ export const error = createAuthEndpoint(
|
|||||||
"/error",
|
"/error",
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
metadata: HIDE_METADATA,
|
metadata: {
|
||||||
|
...HIDE_METADATA,
|
||||||
|
openapi: {
|
||||||
|
description: "Displays an error page",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"text/html": {
|
||||||
|
schema: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const query =
|
const query =
|
||||||
|
|||||||
@@ -37,15 +37,47 @@ export const forgetPassword = createAuthEndpoint(
|
|||||||
/**
|
/**
|
||||||
* The email address of the user to send a password reset email to.
|
* The email address of the user to send a password reset email to.
|
||||||
*/
|
*/
|
||||||
email: z.string().email(),
|
email: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"The email address of the user to send a password reset email to",
|
||||||
|
})
|
||||||
|
.email(),
|
||||||
/**
|
/**
|
||||||
* The URL to redirect the user to reset their password.
|
* The URL to redirect the user to reset their password.
|
||||||
* If the token isn't valid or expired, it'll be redirected with a query parameter `?
|
* If the token isn't valid or expired, it'll be redirected with a query parameter `?
|
||||||
* error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?
|
* error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?
|
||||||
* token=VALID_TOKEN
|
* token=VALID_TOKEN
|
||||||
*/
|
*/
|
||||||
redirectTo: z.string().optional(),
|
redirectTo: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Send a password reset email to the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.options.emailAndPassword?.sendResetPassword) {
|
if (!ctx.context.options.emailAndPassword?.sendResetPassword) {
|
||||||
@@ -108,8 +140,32 @@ export const forgetPasswordCallback = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
query: z.object({
|
query: z.object({
|
||||||
callbackURL: z.string(),
|
callbackURL: z.string({
|
||||||
|
description: "The URL to redirect the user to reset their password",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Redirects the user to the callback URL with the token",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const { token } = ctx.params;
|
const { token } = ctx.params;
|
||||||
@@ -144,9 +200,37 @@ export const resetPassword = createAuthEndpoint(
|
|||||||
),
|
),
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
newPassword: z.string(),
|
newPassword: z.string({
|
||||||
token: z.string().optional(),
|
description: "The new password to set",
|
||||||
|
}),
|
||||||
|
token: z
|
||||||
|
.string({
|
||||||
|
description: "The token to reset the password",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Reset the password for a user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const token =
|
const token =
|
||||||
|
|||||||
@@ -5,7 +5,29 @@ export const ok = createAuthEndpoint(
|
|||||||
"/ok",
|
"/ok",
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
metadata: HIDE_METADATA,
|
metadata: {
|
||||||
|
...HIDE_METADATA,
|
||||||
|
openapi: {
|
||||||
|
description: "Check if the API is working",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
ok: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
|
|||||||
@@ -26,13 +26,50 @@ export const getSession = <Option extends BetterAuthOptions>() =>
|
|||||||
* If cookie cache is enabled, it will disable the cache
|
* If cookie cache is enabled, it will disable the cache
|
||||||
* and fetch the session from the database
|
* and fetch the session from the database
|
||||||
*/
|
*/
|
||||||
disableCookieCache: z.boolean().optional(),
|
disableCookieCache: z
|
||||||
|
.boolean({
|
||||||
|
description:
|
||||||
|
"Disable cookie cache and fetch session from database",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
metadata: {
|
metadata: {
|
||||||
openapi: {
|
openapi: {
|
||||||
tags: ["Session"],
|
description: "Get the current session",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
session: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
$ref: "#/components/schemas/User",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -243,6 +280,37 @@ export const listSessions = <Option extends BetterAuthOptions>() =>
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "List all active sessions for the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const sessions = await ctx.context.internalAdapter.listSessions(
|
const sessions = await ctx.context.internalAdapter.listSessions(
|
||||||
@@ -265,10 +333,32 @@ export const revokeSession = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
token: z.string(),
|
token: z.string({
|
||||||
|
description: "The token to revoke",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Revoke a single session",
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["token"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const token = ctx.body.token;
|
const token = ctx.body.token;
|
||||||
@@ -306,6 +396,29 @@ export const revokeSessions = createAuthEndpoint(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Revoke all sessions for the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["status"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
try {
|
try {
|
||||||
@@ -333,6 +446,29 @@ export const revokeOtherSessions = createAuthEndpoint(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description:
|
||||||
|
"Revoke all other sessions for the user except the current one",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
|
|||||||
@@ -25,25 +25,41 @@ export const signInSocial = createAuthEndpoint(
|
|||||||
* Callback URL to redirect to after the user
|
* Callback URL to redirect to after the user
|
||||||
* has signed in.
|
* has signed in.
|
||||||
*/
|
*/
|
||||||
callbackURL: z.string().optional(),
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"Callback URL to redirect to after the user has signed in",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* Callback url to redirect to if an error happens
|
* Callback url to redirect to if an error happens
|
||||||
*
|
*
|
||||||
* If it's initiated from the client sdk this defaults to
|
* If it's initiated from the client sdk this defaults to
|
||||||
* the current url.
|
* the current url.
|
||||||
*/
|
*/
|
||||||
errorCallbackURL: z.string().optional(),
|
errorCallbackURL: z
|
||||||
|
.string({
|
||||||
|
description: "Callback URL to redirect to if an error happens",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* OAuth2 provider to use`
|
* OAuth2 provider to use`
|
||||||
*/
|
*/
|
||||||
provider: z.enum(socialProviderList),
|
provider: z.enum(socialProviderList, {
|
||||||
|
description: "OAuth2 provider to use",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* Disable automatic redirection to the provider
|
* Disable automatic redirection to the provider
|
||||||
*
|
*
|
||||||
* This is useful if you want to handle the redirection
|
* This is useful if you want to handle the redirection
|
||||||
* yourself like in a popup or a different tab.
|
* yourself like in a popup or a different tab.
|
||||||
*/
|
*/
|
||||||
disableRedirect: z.boolean().optional(),
|
disableRedirect: z
|
||||||
|
.boolean({
|
||||||
|
description:
|
||||||
|
"Disable automatic redirection to the provider. Useful for handling the redirection yourself",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* ID token from the provider
|
* ID token from the provider
|
||||||
*
|
*
|
||||||
@@ -60,26 +76,80 @@ export const signInSocial = createAuthEndpoint(
|
|||||||
/**
|
/**
|
||||||
* ID token from the provider
|
* ID token from the provider
|
||||||
*/
|
*/
|
||||||
token: z.string(),
|
token: z.string({
|
||||||
|
description: "ID token from the provider",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* The nonce used to generate the token
|
* The nonce used to generate the token
|
||||||
*/
|
*/
|
||||||
nonce: z.string().optional(),
|
nonce: z
|
||||||
|
.string({
|
||||||
|
description: "Nonce used to generate the token",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* Access token from the provider
|
* Access token from the provider
|
||||||
*/
|
*/
|
||||||
accessToken: z.string().optional(),
|
accessToken: z
|
||||||
|
.string({
|
||||||
|
description: "Access token from the provider",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* Refresh token from the provider
|
* Refresh token from the provider
|
||||||
*/
|
*/
|
||||||
refreshToken: z.string().optional(),
|
refreshToken: z
|
||||||
|
.string({
|
||||||
|
description: "Refresh token from the provider",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* Expiry date of the token
|
* Expiry date of the token
|
||||||
*/
|
*/
|
||||||
expiresAt: z.number().optional(),
|
expiresAt: z
|
||||||
|
.number({
|
||||||
|
description: "Expiry date of the token",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
"ID token from the provider to sign in the user with id token",
|
||||||
|
},
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Sign in with a social provider",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
session: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
redirect: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["session", "user", "url", "redirect"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const provider = c.context.socialProviders.find(
|
const provider = c.context.socialProviders.find(
|
||||||
@@ -192,22 +262,69 @@ export const signInEmail = createAuthEndpoint(
|
|||||||
/**
|
/**
|
||||||
* Email of the user
|
* Email of the user
|
||||||
*/
|
*/
|
||||||
email: z.string(),
|
email: z.string({
|
||||||
|
description: "Email of the user",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* Password of the user
|
* Password of the user
|
||||||
*/
|
*/
|
||||||
password: z.string(),
|
password: z.string({
|
||||||
|
description: "Password of the user",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* Callback URL to use as a redirect for email
|
* Callback URL to use as a redirect for email
|
||||||
* verification and for possible redirects
|
* verification and for possible redirects
|
||||||
*/
|
*/
|
||||||
callbackURL: z.string().optional(),
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"Callback URL to use as a redirect for email verification",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
/**
|
/**
|
||||||
* If this is false, the session will not be remembered
|
* If this is false, the session will not be remembered
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
rememberMe: z.boolean().default(true).optional(),
|
rememberMe: z
|
||||||
|
.boolean({
|
||||||
|
description:
|
||||||
|
"If this is false, the session will not be remembered. Default is `true`.",
|
||||||
|
})
|
||||||
|
.default(true)
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Sign in with email and password",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
session: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
redirect: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["session", "user", "url", "redirect"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.options?.emailAndPassword?.enabled) {
|
if (!ctx.context.options?.emailAndPassword?.enabled) {
|
||||||
|
|||||||
@@ -8,6 +8,28 @@ export const signOut = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Sign out the current user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const sessionCookieToken = await ctx.getSignedCookie(
|
const sessionCookieToken = await ctx.getSignedCookie(
|
||||||
|
|||||||
@@ -29,6 +29,60 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
|||||||
password: ZodString;
|
password: ZodString;
|
||||||
}> &
|
}> &
|
||||||
toZod<AdditionalUserFieldsInput<O>>,
|
toZod<AdditionalUserFieldsInput<O>>,
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Sign up a user using email and password",
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "The name of the user",
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: "string",
|
||||||
|
description: "The email of the user",
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: "string",
|
||||||
|
description: "The password of the user",
|
||||||
|
},
|
||||||
|
callbackURL: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The URL to use for email verification callback",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["name", "email", "password"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
session: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.options.emailAndPassword?.enabled) {
|
if (!ctx.context.options.emailAndPassword?.enabled) {
|
||||||
|
|||||||
@@ -20,6 +20,47 @@ export const updateUser = <O extends BetterAuthOptions>() =>
|
|||||||
}> &
|
}> &
|
||||||
toZod<AdditionalUserFieldsInput<O>>,
|
toZod<AdditionalUserFieldsInput<O>>,
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Update the current user",
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "The name of the user",
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
type: "string",
|
||||||
|
description: "The image of the user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const body = ctx.body as {
|
const body = ctx.body as {
|
||||||
@@ -74,18 +115,49 @@ export const changePassword = createAuthEndpoint(
|
|||||||
/**
|
/**
|
||||||
* The new password to set
|
* The new password to set
|
||||||
*/
|
*/
|
||||||
newPassword: z.string(),
|
newPassword: z.string({
|
||||||
|
description: "The new password to set",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* The current password of the user
|
* The current password of the user
|
||||||
*/
|
*/
|
||||||
currentPassword: z.string(),
|
currentPassword: z.string({
|
||||||
|
description: "The current password",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* revoke all sessions that are not the
|
* revoke all sessions that are not the
|
||||||
* current one logged in by the user
|
* current one logged in by the user
|
||||||
*/
|
*/
|
||||||
revokeOtherSessions: z.boolean().optional(),
|
revokeOtherSessions: z
|
||||||
|
.boolean({
|
||||||
|
description: "Revoke all other sessions",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Change the password of the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
user: {
|
||||||
|
description: "The user object",
|
||||||
|
$ref: "#/components/schemas/User",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const { newPassword, currentPassword, revokeOtherSessions } = ctx.body;
|
const { newPassword, currentPassword, revokeOtherSessions } = ctx.body;
|
||||||
@@ -215,9 +287,28 @@ export const deleteUser = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
password: z.string(),
|
password: z.string({
|
||||||
|
description: "The password of the user",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Delete the user",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const { password } = ctx.body;
|
const { password } = ctx.body;
|
||||||
@@ -259,10 +350,42 @@ export const changeEmail = createAuthEndpoint(
|
|||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
body: z.object({
|
body: z.object({
|
||||||
newEmail: z.string().email(),
|
newEmail: z
|
||||||
callbackURL: z.string().optional(),
|
.string({
|
||||||
|
description: "The new email to set",
|
||||||
|
})
|
||||||
|
.email(),
|
||||||
|
callbackURL: z
|
||||||
|
.string({
|
||||||
|
description: "The URL to redirect to after email verification",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
use: [sessionMiddleware],
|
use: [sessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
user: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.options.user?.changeEmail?.enabled) {
|
if (!ctx.context.options.user?.changeEmail?.enabled) {
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ export * from "./email-otp";
|
|||||||
export * from "./one-tap";
|
export * from "./one-tap";
|
||||||
export * from "./oauth-proxy";
|
export * from "./oauth-proxy";
|
||||||
export * from "./custom-session";
|
export * from "./custom-session";
|
||||||
|
export * from "./open-api";
|
||||||
|
|||||||
434
packages/better-auth/src/plugins/open-api/generator.ts
Normal file
434
packages/better-auth/src/plugins/open-api/generator.ts
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
import type { Endpoint, EndpointOptions } from "better-call";
|
||||||
|
import { ZodObject, ZodOptional, ZodSchema } from "zod";
|
||||||
|
import type { OpenAPISchemaType, OpenAPIParameter } from "better-call";
|
||||||
|
import type { AuthContext, BetterAuthOptions } from "better-auth";
|
||||||
|
import { getEndpoints } from "better-auth/api";
|
||||||
|
import { getAuthTables } from "../../db";
|
||||||
|
|
||||||
|
interface Path {
|
||||||
|
get?: {
|
||||||
|
tags?: string[];
|
||||||
|
operationId?: string;
|
||||||
|
description?: string;
|
||||||
|
security?: [{ bearerAuth: string[] }];
|
||||||
|
parameters?: OpenAPIParameter[];
|
||||||
|
responses?: {
|
||||||
|
[key in string]: {
|
||||||
|
description?: string;
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type?: OpenAPISchemaType;
|
||||||
|
properties?: Record<string, any>;
|
||||||
|
required?: string[];
|
||||||
|
$ref?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
post?: {
|
||||||
|
tags?: string[];
|
||||||
|
operationId?: string;
|
||||||
|
description?: string;
|
||||||
|
security?: [{ bearerAuth: string[] }];
|
||||||
|
parameters?: OpenAPIParameter[];
|
||||||
|
requestBody?: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type?: OpenAPISchemaType;
|
||||||
|
properties?: Record<string, any>;
|
||||||
|
required?: string[];
|
||||||
|
$ref?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses?: {
|
||||||
|
[key in string]: {
|
||||||
|
description?: string;
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type?: OpenAPISchemaType;
|
||||||
|
properties?: Record<string, any>;
|
||||||
|
required?: string[];
|
||||||
|
$ref?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const paths: Record<string, Path> = {};
|
||||||
|
|
||||||
|
function getTypeFromZodType(zodType: ZodSchema) {
|
||||||
|
switch (zodType.constructor.name) {
|
||||||
|
case "ZodString":
|
||||||
|
return "string";
|
||||||
|
case "ZodNumber":
|
||||||
|
return "number";
|
||||||
|
case "ZodBoolean":
|
||||||
|
return "boolean";
|
||||||
|
case "ZodObject":
|
||||||
|
return "object";
|
||||||
|
case "ZodArray":
|
||||||
|
return "array";
|
||||||
|
default:
|
||||||
|
return "string";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParameters(options: EndpointOptions) {
|
||||||
|
const parameters: OpenAPIParameter[] = [];
|
||||||
|
if (options.metadata?.openapi?.parameters) {
|
||||||
|
parameters.push(...options.metadata.openapi.parameters);
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
if (options.query instanceof ZodObject) {
|
||||||
|
Object.entries(options.query.shape).forEach(([key, value]) => {
|
||||||
|
if (value instanceof ZodSchema) {
|
||||||
|
parameters.push({
|
||||||
|
name: key,
|
||||||
|
in: "query",
|
||||||
|
schema: {
|
||||||
|
type: getTypeFromZodType(value),
|
||||||
|
...("minLength" in value && value.minLength
|
||||||
|
? {
|
||||||
|
minLength: value.minLength as number,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
description: value.description,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRequestBody(options: EndpointOptions): any {
|
||||||
|
if (options.metadata?.openapi?.requestBody) {
|
||||||
|
return options.metadata.openapi.requestBody;
|
||||||
|
}
|
||||||
|
if (!options.body) return undefined;
|
||||||
|
if (
|
||||||
|
options.body instanceof ZodObject ||
|
||||||
|
options.body instanceof ZodOptional
|
||||||
|
) {
|
||||||
|
// @ts-ignore
|
||||||
|
const shape = options.body.shape;
|
||||||
|
if (!shape) return undefined;
|
||||||
|
const properties: Record<string, any> = {};
|
||||||
|
const required: string[] = [];
|
||||||
|
Object.entries(shape).forEach(([key, value]) => {
|
||||||
|
if (value instanceof ZodSchema) {
|
||||||
|
properties[key] = {
|
||||||
|
type: getTypeFromZodType(value),
|
||||||
|
description: value.description,
|
||||||
|
};
|
||||||
|
if (!(value instanceof ZodOptional)) {
|
||||||
|
required.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
required:
|
||||||
|
options.body instanceof ZodOptional
|
||||||
|
? false
|
||||||
|
: options.body
|
||||||
|
? true
|
||||||
|
: false,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties,
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResponse(responses?: Record<string, any>) {
|
||||||
|
return {
|
||||||
|
"400": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["message"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"Bad Request. Usually due to missing parameters, or invalid parameters.",
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["message"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Unauthorized. Due to missing or invalid authentication.",
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"Forbidden. You do not have permission to access this resource or to perform this action.",
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Not Found. The requested resource was not found.",
|
||||||
|
},
|
||||||
|
"429": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"Too Many Requests. You have exceeded the rate limit. Try again later.",
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
"Internal Server Error. This is a problem with the server that you cannot fix.",
|
||||||
|
},
|
||||||
|
...responses,
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generator(ctx: AuthContext, options: BetterAuthOptions) {
|
||||||
|
const baseEndpoints = getEndpoints(ctx, {
|
||||||
|
...options,
|
||||||
|
plugins: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const tables = getAuthTables(options);
|
||||||
|
const models = Object.entries(tables).reduce((acc, [key, value]) => {
|
||||||
|
const modelName = key.charAt(0).toUpperCase() + key.slice(1);
|
||||||
|
// @ts-ignore
|
||||||
|
acc[modelName] = {
|
||||||
|
type: "object",
|
||||||
|
properties: Object.entries(value.fields).reduce(
|
||||||
|
(acc, [key, value]) => {
|
||||||
|
acc[key] = {
|
||||||
|
type: value.type,
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, any>,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
schemas: {
|
||||||
|
...models,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.entries(baseEndpoints.api).forEach(([_, value]) => {
|
||||||
|
const options = value.options as EndpointOptions;
|
||||||
|
if (options.metadata?.SERVER_ONLY) return;
|
||||||
|
if (options.method === "GET") {
|
||||||
|
paths[value.path] = {
|
||||||
|
get: {
|
||||||
|
tags: ["Default", ...(options.metadata?.openapi?.tags || [])],
|
||||||
|
description: options.metadata?.openapi?.description,
|
||||||
|
operationId: options.metadata?.openapi?.operationId,
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parameters: getParameters(options),
|
||||||
|
responses: getResponse(options.metadata?.openapi?.responses),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.method === "POST") {
|
||||||
|
const body = getRequestBody(options);
|
||||||
|
paths[value.path] = {
|
||||||
|
post: {
|
||||||
|
tags: ["Default", ...(options.metadata?.openapi?.tags || [])],
|
||||||
|
description: options.metadata?.openapi?.description,
|
||||||
|
operationId: options.metadata?.openapi?.operationId,
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parameters: getParameters(options),
|
||||||
|
...(body
|
||||||
|
? { requestBody: body }
|
||||||
|
: {
|
||||||
|
requestBody: {
|
||||||
|
//set body none
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
responses: getResponse(options.metadata?.openapi?.responses),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const plugin of options.plugins || []) {
|
||||||
|
if (plugin.id === "open-api") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const pluginEndpoints = getEndpoints(ctx, {
|
||||||
|
...options,
|
||||||
|
plugins: [plugin],
|
||||||
|
});
|
||||||
|
const api = Object.keys(pluginEndpoints.api)
|
||||||
|
.map((key) => {
|
||||||
|
if (
|
||||||
|
baseEndpoints.api[key as keyof typeof baseEndpoints.api] === undefined
|
||||||
|
) {
|
||||||
|
return pluginEndpoints.api[key as keyof typeof pluginEndpoints.api];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter((x) => x !== null) as Endpoint[];
|
||||||
|
Object.entries(api).forEach(([key, value]) => {
|
||||||
|
const options = value.options as EndpointOptions;
|
||||||
|
if (options.metadata?.SERVER_ONLY) return;
|
||||||
|
if (options.method === "GET") {
|
||||||
|
paths[value.path] = {
|
||||||
|
get: {
|
||||||
|
tags: options.metadata?.openapi?.tags || [
|
||||||
|
plugin.id.charAt(0).toUpperCase() + plugin.id.slice(1),
|
||||||
|
],
|
||||||
|
description: options.metadata?.openapi?.description,
|
||||||
|
operationId: options.metadata?.openapi?.operationId,
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parameters: getParameters(options),
|
||||||
|
responses: getResponse(options.metadata?.openapi?.responses),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (options.method === "POST") {
|
||||||
|
paths[value.path] = {
|
||||||
|
post: {
|
||||||
|
tags: options.metadata?.openapi?.tags || [
|
||||||
|
plugin.id.charAt(0).toUpperCase() + plugin.id.slice(1),
|
||||||
|
],
|
||||||
|
description: options.metadata?.openapi?.description,
|
||||||
|
operationId: options.metadata?.openapi?.operationId,
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parameters: getParameters(options),
|
||||||
|
requestBody: getRequestBody(options),
|
||||||
|
responses: getResponse(options.metadata?.openapi?.responses),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
openapi: "3.1.1",
|
||||||
|
info: {
|
||||||
|
title: "Better Auth",
|
||||||
|
description: "API Reference for your Better Auth Instance",
|
||||||
|
},
|
||||||
|
components,
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
apiKeyCookie: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: ctx.baseURL,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
name: "Default",
|
||||||
|
description:
|
||||||
|
"Default endpoints that are included with Better Auth by default. These endpoints are not part of any plugin.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
paths,
|
||||||
|
};
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { BetterAuthPlugin } from "better-auth";
|
import type { BetterAuthPlugin } from "better-auth";
|
||||||
import { createAuthEndpoint } from "better-auth/plugins";
|
import { createAuthEndpoint } from "better-auth/plugins";
|
||||||
import { getEndpoints } from "better-auth/api";
|
|
||||||
import { generator } from "./generator";
|
import { generator } from "./generator";
|
||||||
|
import { logo } from "./logo";
|
||||||
|
|
||||||
const getHTML = (apiReference: Record<string, any>) => `<!doctype html>
|
const getHTML = (apiReference: Record<string, any>) => `<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
@@ -18,7 +18,20 @@ const getHTML = (apiReference: Record<string, any>) => `<!doctype html>
|
|||||||
type="application/json">
|
type="application/json">
|
||||||
${JSON.stringify(apiReference)}
|
${JSON.stringify(apiReference)}
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
<script>
|
||||||
|
var configuration = {
|
||||||
|
favicon: "data:image/svg+xml;utf8,${encodeURIComponent(logo)}",
|
||||||
|
theme: "saturn",
|
||||||
|
metaData: {
|
||||||
|
title: "Better Auth API",
|
||||||
|
description: "API Reference for your Better Auth Instance",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('api-reference').dataset.configuration =
|
||||||
|
JSON.stringify(configuration)
|
||||||
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
|
|
||||||
@@ -27,7 +40,7 @@ export const openAPI = () => {
|
|||||||
id: "open-api",
|
id: "open-api",
|
||||||
endpoints: {
|
endpoints: {
|
||||||
openAPI: createAuthEndpoint(
|
openAPI: createAuthEndpoint(
|
||||||
"/api-reference",
|
"/reference",
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
10
packages/better-auth/src/plugins/open-api/logo.ts
Normal file
10
packages/better-auth/src/plugins/open-api/logo.ts
Normal file
File diff suppressed because one or more lines are too long
@@ -260,6 +260,48 @@ export const organization = <O extends OrganizationOptions>(options?: O) => {
|
|||||||
}>;
|
}>;
|
||||||
}>,
|
}>,
|
||||||
use: [orgSessionMiddleware],
|
use: [orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Check if the user has permission",
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
permission: {
|
||||||
|
type: "object",
|
||||||
|
description: "The permission to check",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["permission"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
error: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["success"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.session.session.activeOrganizationId) {
|
if (!ctx.context.session.session.activeOrganizationId) {
|
||||||
|
|||||||
@@ -16,11 +16,73 @@ export const createInvitation = <O extends OrganizationOptions | undefined>(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
email: z.string(),
|
email: z.string({
|
||||||
role: z.string() as unknown as InferRolesFromOption<O>,
|
description: "The email address of the user to invite",
|
||||||
organizationId: z.string().optional(),
|
}),
|
||||||
resend: z.boolean().optional(),
|
role: z.string({
|
||||||
|
description: "The role to assign to the user",
|
||||||
|
}) as unknown as InferRolesFromOption<O>,
|
||||||
|
organizationId: z
|
||||||
|
.string({
|
||||||
|
description: "The organization ID to invite the user to",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
resend: z
|
||||||
|
.boolean({
|
||||||
|
description:
|
||||||
|
"Resend the invitation email, if the user is already invited",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Invite a user to an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
inviterId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
"id",
|
||||||
|
"email",
|
||||||
|
"role",
|
||||||
|
"organizationId",
|
||||||
|
"inviterId",
|
||||||
|
"status",
|
||||||
|
"expiresAt",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
if (!ctx.context.orgOptions.sendInvitationEmail) {
|
if (!ctx.context.orgOptions.sendInvitationEmail) {
|
||||||
@@ -121,9 +183,36 @@ export const acceptInvitation = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
invitationId: z.string(),
|
invitationId: z.string({
|
||||||
|
description: "The ID of the invitation to accept",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Accept an invitation to an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
invitation: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -176,9 +265,36 @@ export const rejectInvitation = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
invitationId: z.string(),
|
invitationId: z.string({
|
||||||
|
description: "The ID of the invitation to reject",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Reject an invitation to an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
invitation: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
type: "null",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -214,9 +330,31 @@ export const cancelInvitation = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
invitationId: z.string(),
|
invitationId: z.string({
|
||||||
|
description: "The ID of the invitation to cancel",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
openapi: {
|
||||||
|
description: "Cancel an invitation to an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
invitation: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -259,8 +397,71 @@ export const getInvitation = createAuthEndpoint(
|
|||||||
use: [orgMiddleware],
|
use: [orgMiddleware],
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
query: z.object({
|
query: z.object({
|
||||||
id: z.string(),
|
id: z.string({
|
||||||
|
description: "The ID of the invitation to get",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Get an invitation by ID",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
inviterId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationName: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationSlug: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
inviterEmail: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
"id",
|
||||||
|
"email",
|
||||||
|
"role",
|
||||||
|
"organizationId",
|
||||||
|
"inviterId",
|
||||||
|
"status",
|
||||||
|
"expiresAt",
|
||||||
|
"organizationName",
|
||||||
|
"organizationSlug",
|
||||||
|
"inviterEmail",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = await getSessionFromCtx(ctx);
|
const session = await getSessionFromCtx(ctx);
|
||||||
|
|||||||
@@ -11,13 +11,58 @@ export const removeMember = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
memberIdOrEmail: z.string(),
|
memberIdOrEmail: z.string({
|
||||||
|
description: "The ID or email of the member to remove",
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* If not provided, the active organization will be used
|
* If not provided, the active organization will be used
|
||||||
*/
|
*/
|
||||||
organizationId: z.string().optional(),
|
organizationId: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"The ID of the organization to remove the member from. If not provided, the active organization will be used",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Remove a member from an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
member: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["id", "userId", "organizationId", "role"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["member"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -110,6 +155,44 @@ export const updateMemberRole = <O extends OrganizationOptions>(option: O) =>
|
|||||||
organizationId: z.string().optional(),
|
organizationId: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Update the role of a member in an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
member: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["id", "userId", "organizationId", "role"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["member"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -184,6 +267,38 @@ export const getActiveMember = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Get the active member in the organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
organizationId: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ["id", "userId", "organizationId", "role"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
|
|||||||
@@ -11,13 +11,49 @@ export const createOrganization = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
name: z.string(),
|
name: z.string({
|
||||||
slug: z.string(),
|
description: "The name of the organization",
|
||||||
userId: z.string().optional(),
|
}),
|
||||||
logo: z.string().optional(),
|
slug: z.string({
|
||||||
metadata: z.record(z.string(), z.any()).optional(),
|
description: "The slug of the organization",
|
||||||
|
}),
|
||||||
|
userId: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server.",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
logo: z
|
||||||
|
.string({
|
||||||
|
description: "The logo of the organization",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
metadata: z
|
||||||
|
.record(z.string(), z.any(), {
|
||||||
|
description: "The metadata of the organization",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Create an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
description: "The organization that was created",
|
||||||
|
$ref: "#/components/schemas/Organization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const user = ctx.context.session.user;
|
const user = ctx.context.session.user;
|
||||||
@@ -89,15 +125,46 @@ export const updateOrganization = createAuthEndpoint(
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
data: z
|
data: z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().optional(),
|
name: z
|
||||||
slug: z.string().optional(),
|
.string({
|
||||||
logo: z.string().optional(),
|
description: "The name of the organization",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
slug: z
|
||||||
|
.string({
|
||||||
|
description: "The slug of the organization",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
logo: z
|
||||||
|
.string({
|
||||||
|
description: "The logo of the organization",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.partial(),
|
.partial(),
|
||||||
organizationId: z.string().optional(),
|
organizationId: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
use: [orgMiddleware],
|
use: [orgMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Update an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
description: "The updated organization",
|
||||||
|
$ref: "#/components/schemas/Organization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = await ctx.context.getSession(ctx);
|
const session = await ctx.context.getSession(ctx);
|
||||||
@@ -162,10 +229,30 @@ export const deleteOrganization = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
organizationId: z.string(),
|
organizationId: z.string({
|
||||||
|
description: "The organization id to delete",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
use: [orgMiddleware],
|
use: [orgMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Delete an organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "string",
|
||||||
|
description: "The organization id that was deleted",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = await ctx.context.getSession(ctx);
|
const session = await ctx.context.getSession(ctx);
|
||||||
@@ -230,11 +317,34 @@ export const getFullOrganization = createAuthEndpoint(
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
query: z.optional(
|
query: z.optional(
|
||||||
z.object({
|
z.object({
|
||||||
organizationId: z.string().optional(),
|
organizationId: z
|
||||||
|
.string({
|
||||||
|
description: "The organization id to get",
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
requireHeaders: true,
|
requireHeaders: true,
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Get the full organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
description: "The organization",
|
||||||
|
$ref: "#/components/schemas/Organization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const session = ctx.context.session;
|
const session = ctx.context.session;
|
||||||
@@ -261,9 +371,34 @@ export const setActiveOrganization = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
organizationId: z.string().nullable().optional(),
|
organizationId: z
|
||||||
|
.string({
|
||||||
|
description:
|
||||||
|
"The organization id to set as active. Can be null to unset the active organization",
|
||||||
|
})
|
||||||
|
.nullable()
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
use: [orgSessionMiddleware, orgMiddleware],
|
use: [orgSessionMiddleware, orgMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "Set the active organization",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
description: "The organization",
|
||||||
|
$ref: "#/components/schemas/Organization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
|
const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
|
||||||
@@ -319,6 +454,26 @@ export const listOrganizations = createAuthEndpoint(
|
|||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
use: [orgMiddleware, orgSessionMiddleware],
|
use: [orgMiddleware, orgSessionMiddleware],
|
||||||
|
metadata: {
|
||||||
|
openapi: {
|
||||||
|
description: "List all organizations",
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
$ref: "#/components/schemas/Organization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
|
const adapter = getOrgAdapter(ctx.context, ctx.context.orgOptions);
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@better-auth/open-api",
|
|
||||||
"version": "1.0.0-canary.12",
|
|
||||||
"description": "",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"module": "dist/index.mjs",
|
|
||||||
"scripts": {
|
|
||||||
"test": "vitest",
|
|
||||||
"build": "tsup --dts --minify --clean",
|
|
||||||
"dev": "tsup --watch --sourcemap --dts"
|
|
||||||
},
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./dist/index.d.ts",
|
|
||||||
"import": "./dist/index.mjs",
|
|
||||||
"require": "./dist/index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"devDependencies": {
|
|
||||||
"better-auth": "workspace:*"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"better-call": "^0.3.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
import type { Endpoint, EndpointOptions } from "better-call";
|
|
||||||
import { ZodObject, ZodSchema } from "zod";
|
|
||||||
import type { OpenAPISchemaType, OpenAPIParameter } from "better-call";
|
|
||||||
import type { AuthContext, BetterAuthOptions } from "better-auth";
|
|
||||||
import { getEndpoints } from "better-auth/api";
|
|
||||||
|
|
||||||
interface Path {
|
|
||||||
get?: {
|
|
||||||
tags?: string[];
|
|
||||||
operationId?: string;
|
|
||||||
security?: [{ bearerAuth: string[] }];
|
|
||||||
parameters?: OpenAPIParameter[];
|
|
||||||
responses?: {
|
|
||||||
[key in string]: {
|
|
||||||
description?: string;
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type?: OpenAPISchemaType;
|
|
||||||
properties?: Record<string, any>;
|
|
||||||
required?: string[];
|
|
||||||
$ref?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const paths: Record<string, Path> = {};
|
|
||||||
|
|
||||||
function getTypeFromZodType(zodType: ZodSchema) {
|
|
||||||
switch (zodType.constructor.name) {
|
|
||||||
case "ZodString":
|
|
||||||
return "string";
|
|
||||||
case "ZodNumber":
|
|
||||||
return "number";
|
|
||||||
case "ZodBoolean":
|
|
||||||
return "boolean";
|
|
||||||
case "ZodObject":
|
|
||||||
return "object";
|
|
||||||
case "ZodArray":
|
|
||||||
return "array";
|
|
||||||
default:
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParameters(options: EndpointOptions) {
|
|
||||||
const parameters: OpenAPIParameter[] = [];
|
|
||||||
if (options.metadata?.openapi?.parameters) {
|
|
||||||
parameters.push(...options.metadata.openapi.parameters);
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
if (options.query instanceof ZodObject) {
|
|
||||||
Object.entries(options.query.shape).forEach(([key, value]) => {
|
|
||||||
if (value instanceof ZodSchema) {
|
|
||||||
parameters.push({
|
|
||||||
name: key,
|
|
||||||
in: "query",
|
|
||||||
schema: {
|
|
||||||
type: getTypeFromZodType(value),
|
|
||||||
...("minLength" in value && value.minLength
|
|
||||||
? {
|
|
||||||
minLength: value.minLength as number,
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
description: value.description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generator(ctx: AuthContext, options: BetterAuthOptions) {
|
|
||||||
const baseEndpoints = getEndpoints(ctx, {
|
|
||||||
...options,
|
|
||||||
plugins: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.entries(baseEndpoints.api).forEach(([_, value]) => {
|
|
||||||
const options = value.options as EndpointOptions;
|
|
||||||
if (options.method === "GET") {
|
|
||||||
paths[value.path] = {
|
|
||||||
get: {
|
|
||||||
tags: ["core", ...(options.metadata?.openapi?.tags || [])],
|
|
||||||
operationId: options.metadata?.openapi?.operationId,
|
|
||||||
security: [
|
|
||||||
{
|
|
||||||
bearerAuth: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
parameters: getParameters(options),
|
|
||||||
responses: options.metadata?.openapi?.responses || {
|
|
||||||
"200": {
|
|
||||||
description: "Success",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ["message"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ["message"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const plugin of options.plugins || []) {
|
|
||||||
const pluginEndpoints = getEndpoints(ctx, {
|
|
||||||
...options,
|
|
||||||
plugins: [plugin],
|
|
||||||
});
|
|
||||||
const api = Object.keys(pluginEndpoints.api)
|
|
||||||
.map((key) => {
|
|
||||||
if (
|
|
||||||
baseEndpoints.api[key as keyof typeof baseEndpoints.api] === undefined
|
|
||||||
) {
|
|
||||||
return pluginEndpoints.api[key as keyof typeof pluginEndpoints.api];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.filter((x) => x !== null) as Endpoint[];
|
|
||||||
Object.entries(api).forEach(([key, value]) => {
|
|
||||||
const options = value.options as EndpointOptions;
|
|
||||||
if (options.method === "GET") {
|
|
||||||
paths[value.path] = {
|
|
||||||
get: {
|
|
||||||
tags: options.metadata?.openapi?.tags || [plugin.id],
|
|
||||||
operationId: options.metadata?.openapi?.operationId,
|
|
||||||
security: [
|
|
||||||
{
|
|
||||||
bearerAuth: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
parameters: getParameters(options),
|
|
||||||
responses: options.metadata?.openapi?.responses || {
|
|
||||||
"200": {
|
|
||||||
description: "Success",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ["message"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ["message"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = {
|
|
||||||
openapi: "3.1.1",
|
|
||||||
info: {
|
|
||||||
title: "Better Auth Api",
|
|
||||||
description: "API Reference for your Better Auth Instance",
|
|
||||||
},
|
|
||||||
security: [
|
|
||||||
{
|
|
||||||
apiKeyCookie: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
servers: [
|
|
||||||
{
|
|
||||||
url: ctx.baseURL,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
name: "Authentication",
|
|
||||||
description:
|
|
||||||
"Some endpoints are public, but some require authentication. We provide all the required endpoints to create an account and authorize yourself.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
paths,
|
|
||||||
};
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"target": "es2022",
|
|
||||||
"allowJs": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"noEmit": true,
|
|
||||||
"moduleResolution": "Bundler",
|
|
||||||
"moduleDetection": "force",
|
|
||||||
"isolatedModules": true,
|
|
||||||
"verbatimModuleSyntax": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitOverride": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules"],
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { defineConfig } from "tsup";
|
|
||||||
|
|
||||||
export default defineConfig((env) => {
|
|
||||||
return {
|
|
||||||
entry: ["src/index.ts"],
|
|
||||||
format: ["esm", "cjs"],
|
|
||||||
bundle: true,
|
|
||||||
skipNodeModulesBundle: true,
|
|
||||||
external: ["better-call", "better-auth"],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -44,9 +44,6 @@ importers:
|
|||||||
|
|
||||||
demo/nextjs:
|
demo/nextjs:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@better-auth/open-api':
|
|
||||||
specifier: workspace:1.0.0-canary.12
|
|
||||||
version: link:../../packages/open-api
|
|
||||||
'@better-fetch/fetch':
|
'@better-fetch/fetch':
|
||||||
specifier: 1.1.12
|
specifier: 1.1.12
|
||||||
version: 1.1.12
|
version: 1.1.12
|
||||||
@@ -1350,8 +1347,8 @@ importers:
|
|||||||
specifier: ^10.0.1
|
specifier: ^10.0.1
|
||||||
version: 10.0.1(encoding@0.1.13)
|
version: 10.0.1(encoding@0.1.13)
|
||||||
better-call:
|
better-call:
|
||||||
specifier: 0.3.1
|
specifier: 0.3.2
|
||||||
version: 0.3.1
|
version: 0.3.2
|
||||||
consola:
|
consola:
|
||||||
specifier: ^3.2.3
|
specifier: ^3.2.3
|
||||||
version: 3.2.3
|
version: 3.2.3
|
||||||
@@ -1560,16 +1557,6 @@ importers:
|
|||||||
specifier: ^1.6.0
|
specifier: ^1.6.0
|
||||||
version: 1.6.0(@types/node@22.8.6)(happy-dom@15.8.0)(lightningcss@1.27.0)(terser@5.36.0)
|
version: 1.6.0(@types/node@22.8.6)(happy-dom@15.8.0)(lightningcss@1.27.0)(terser@5.36.0)
|
||||||
|
|
||||||
packages/open-api:
|
|
||||||
dependencies:
|
|
||||||
better-call:
|
|
||||||
specifier: ^0.3.0
|
|
||||||
version: 0.3.0
|
|
||||||
devDependencies:
|
|
||||||
better-auth:
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../better-auth
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@algolia/cache-browser-local-storage@4.24.0':
|
'@algolia/cache-browser-local-storage@4.24.0':
|
||||||
@@ -8109,11 +8096,8 @@ packages:
|
|||||||
better-call@0.2.3-beta.2:
|
better-call@0.2.3-beta.2:
|
||||||
resolution: {integrity: sha512-ybOtGcR4pOsHI2XE+urR9zcmK+s0YnhJSx8KDj6ul7MUEyYOiMEnq/bylyH62/7qXuYb9q8Oqkp9NF9vWOZ4Mg==}
|
resolution: {integrity: sha512-ybOtGcR4pOsHI2XE+urR9zcmK+s0YnhJSx8KDj6ul7MUEyYOiMEnq/bylyH62/7qXuYb9q8Oqkp9NF9vWOZ4Mg==}
|
||||||
|
|
||||||
better-call@0.3.0:
|
better-call@0.3.2:
|
||||||
resolution: {integrity: sha512-nBWeQl+O1NCPMkb958VQzVn0AfSWwILGoLCpLbTzz3p0QnsqFYSTe6z8Uzo4p/6Iah8zrRBoLBQvFLUFl80jxA==}
|
resolution: {integrity: sha512-ZYUADh4S4JF3QOIgC0QAm4N9Ifb7v3rOEcwkIxr3UXxd+GCrGmEzv7VDe35o1ldX0Zcb9CX3QfT0jdJoMIKA9w==}
|
||||||
|
|
||||||
better-call@0.3.1:
|
|
||||||
resolution: {integrity: sha512-uJoTAVLHCIrRebBxu2rQ/CPpf7r1c7FrfFIL2OS5dVx1z/64nGMZ5sH2GUtYu22XRjbOGEn7KI9eNkLpIo41CQ==}
|
|
||||||
|
|
||||||
better-opn@3.0.2:
|
better-opn@3.0.2:
|
||||||
resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
|
resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
|
||||||
@@ -25761,15 +25745,7 @@ snapshots:
|
|||||||
set-cookie-parser: 2.7.1
|
set-cookie-parser: 2.7.1
|
||||||
typescript: 5.6.3
|
typescript: 5.6.3
|
||||||
|
|
||||||
better-call@0.3.0:
|
better-call@0.3.2:
|
||||||
dependencies:
|
|
||||||
'@better-fetch/fetch': 1.1.12
|
|
||||||
rou3: 0.5.1
|
|
||||||
set-cookie-parser: 2.7.1
|
|
||||||
uncrypto: 0.1.3
|
|
||||||
zod: 3.23.8
|
|
||||||
|
|
||||||
better-call@0.3.1:
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@better-fetch/fetch': 1.1.12
|
'@better-fetch/fetch': 1.1.12
|
||||||
rou3: 0.5.1
|
rou3: 0.5.1
|
||||||
|
|||||||
Reference in New Issue
Block a user