mirror of
https://github.com/better-auth/better-auth.git
synced 2026-10-26 21:45:40 -05:00
feat: fm integrations
This commit is contained in:
Vendored
+3
@@ -6,5 +6,8 @@
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[svelte]": {
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,10 +1,4 @@
|
||||
import { auth } from "@/lib/auth";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { toNextJsHandler } from "better-auth/next-js";
|
||||
|
||||
const handler = auth.handler;
|
||||
|
||||
export const POST = async (req: NextRequest) => {
|
||||
return handler(req);
|
||||
};
|
||||
|
||||
export { handler as GET };
|
||||
export const { GET, POST } = toNextJsHandler(auth);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import type { auth } from "./auth";
|
||||
import { organization } from "better-auth/client";
|
||||
|
||||
export const authClient = createAuthClient<typeof auth>({
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: "http://localhost:3000/api/auth",
|
||||
authPlugins: [organization],
|
||||
});
|
||||
|
||||
export const {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
dist
|
||||
.solid
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.vinxi
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
.settings/
|
||||
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,32 @@
|
||||
# SolidStart
|
||||
|
||||
Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
|
||||
|
||||
## Creating a project
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm init solid@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm init solid@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Solid apps are built with _presets_, which optimise your project for deployment to different environments.
|
||||
|
||||
By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
|
||||
|
||||
## This project was created with the [Solid CLI](https://solid-cli.netlify.app)
|
||||
@@ -0,0 +1,6 @@
|
||||
// app.config.ts
|
||||
import { defineConfig } from "@solidjs/start/config";
|
||||
var app_config_default = defineConfig({});
|
||||
export {
|
||||
app_config_default as default
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineConfig } from "@solidjs/start/config";
|
||||
|
||||
export default defineConfig({});
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "example-with-tailwindcss",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vinxi dev",
|
||||
"build": "vinxi build",
|
||||
"start": "vinxi start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/router": "^0.14.1",
|
||||
"@solidjs/start": "^1.0.6",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"better-auth": "workspace:0.0.2-beta.8",
|
||||
"postcss": "^8.4.38",
|
||||
"solid-js": "^1.8.18",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"vinxi": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--background-rgb: 214, 219, 220;
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background-rgb: 0, 0, 0;
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: rgb(var(--background-rgb));
|
||||
color: rgb(var(--foreground-rgb));
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Router } from "@solidjs/router";
|
||||
import { FileRoutes } from "@solidjs/start/router";
|
||||
import { Suspense } from "solid-js";
|
||||
import Nav from "~/components/Nav";
|
||||
import "./app.css";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router
|
||||
root={props => (
|
||||
<>
|
||||
<Suspense>{props.children}</Suspense>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<FileRoutes />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { createSignal } from "solid-js";
|
||||
|
||||
export default function Counter() {
|
||||
const [count, setCount] = createSignal(0);
|
||||
return (
|
||||
<button
|
||||
class="w-[200px] rounded-full bg-gray-100 border-2 border-gray-300 focus:border-gray-400 active:border-gray-400 px-[2rem] py-[1rem]"
|
||||
onClick={() => setCount(count() + 1)}
|
||||
>
|
||||
Clicks: {count()}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { useLocation } from "@solidjs/router";
|
||||
|
||||
export default function Nav() {
|
||||
const location = useLocation();
|
||||
const active = (path: string) =>
|
||||
path == location.pathname ? "border-sky-600" : "border-transparent hover:border-sky-600";
|
||||
return (
|
||||
<nav class="bg-sky-800">
|
||||
<ul class="container flex items-center p-3 text-gray-200">
|
||||
<li class={`border-b-2 ${active("/")} mx-1.5 sm:mx-6`}>
|
||||
<a href="/">Home</a>
|
||||
</li>
|
||||
<li class={`border-b-2 ${active("/about")} mx-1.5 sm:mx-6`}>
|
||||
<a href="/about">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// @refresh reload
|
||||
import { mount, StartClient } from "@solidjs/start/client";
|
||||
|
||||
mount(() => <StartClient />, document.getElementById("app")!);
|
||||
@@ -0,0 +1,21 @@
|
||||
// @refresh reload
|
||||
import { createHandler, StartServer } from "@solidjs/start/server";
|
||||
|
||||
export default createHandler(() => (
|
||||
<StartServer
|
||||
document={({ assets, children, scripts }) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
{assets}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">{children}</div>
|
||||
{scripts}
|
||||
</body>
|
||||
</html>
|
||||
)}
|
||||
/>
|
||||
));
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="@solidjs/start/env" />
|
||||
@@ -0,0 +1,15 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { github } from "better-auth/social-providers";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: {
|
||||
provider: "sqlite",
|
||||
url: "./db.sqlite",
|
||||
},
|
||||
socialProvider: [
|
||||
github({
|
||||
clientId: process.env.GITHUB_CLIENT_ID as string,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
import { createAuthClient } from "better-auth/solid";
|
||||
export const client = createAuthClient();
|
||||
@@ -0,0 +1,25 @@
|
||||
import { A } from "@solidjs/router";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<main class="text-center mx-auto text-gray-700 p-4">
|
||||
<h1 class="max-6-xs text-6xl text-sky-700 font-thin uppercase my-16">Not Found</h1>
|
||||
<p class="mt-8">
|
||||
Visit{" "}
|
||||
<a href="https://solidjs.com" target="_blank" class="text-sky-600 hover:underline">
|
||||
solidjs.com
|
||||
</a>{" "}
|
||||
to learn how to build Solid apps.
|
||||
</p>
|
||||
<p class="my-4">
|
||||
<A href="/" class="text-sky-600 hover:underline">
|
||||
Home
|
||||
</A>
|
||||
{" - "}
|
||||
<A href="/about" class="text-sky-600 hover:underline">
|
||||
About Page
|
||||
</A>
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { A } from "@solidjs/router";
|
||||
import Counter from "~/components/Counter";
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<main class="text-center mx-auto text-gray-700 p-4">
|
||||
<h1 class="max-6-xs text-6xl text-sky-700 font-thin uppercase my-16">About Page</h1>
|
||||
<Counter />
|
||||
<p class="mt-8">
|
||||
Visit{" "}
|
||||
<a href="https://solidjs.com" target="_blank" class="text-sky-600 hover:underline">
|
||||
solidjs.com
|
||||
</a>{" "}
|
||||
to learn how to build Solid apps.
|
||||
</p>
|
||||
<p class="my-4">
|
||||
<A href="/" class="text-sky-600 hover:underline">
|
||||
Home
|
||||
</A>
|
||||
{" - "}
|
||||
<span>About Page</span>
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { auth } from "~/lib/auth";
|
||||
import { toSolidStartHandler } from "better-auth/solid-start";
|
||||
|
||||
export const { GET, POST } = toSolidStartHandler(auth);
|
||||
@@ -0,0 +1,31 @@
|
||||
import { client } from "~/lib/client";
|
||||
|
||||
|
||||
export default function Home() {
|
||||
const session = client.useSession()
|
||||
return (
|
||||
<main class="text-center mx-auto text-gray-700 p-4 min-h-screen flex flex-col items-center justify-center">
|
||||
{
|
||||
session() ? <div class="flex flex-col gap-2 border border-blue-400/10 px-6 py-5">
|
||||
<p class="text-2xl text-white">
|
||||
{session()?.user.name}
|
||||
</p>
|
||||
<p>
|
||||
{session()?.user.email}
|
||||
</p>
|
||||
<button class="bg-sky-600 text-white px-4 py-2 rounded-md" onclick={async () => {
|
||||
await client.signOut()
|
||||
}}>
|
||||
Signout
|
||||
</button>
|
||||
</div> : <button class="bg-sky-600 text-white px-4 py-2 rounded-md" onclick={async () => {
|
||||
await client.signIn.social({
|
||||
provider: "github",
|
||||
})
|
||||
}}>
|
||||
Continue with github
|
||||
</button>
|
||||
}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
plugins: []
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"types": ["vinxi/types/client"],
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
@@ -0,0 +1 @@
|
||||
engine-strict=true
|
||||
@@ -0,0 +1,38 @@
|
||||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "svelte",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev --port 3000",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^3.6.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"better-auth": "workspace:0.0.2-beta.8"
|
||||
}
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
import { auth } from "$lib/auth";
|
||||
import { svelteKitHandler } from "better-auth/svelte-kit";
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
return svelteKitHandler({ event, resolve, auth });
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { env } from "$env/dynamic/private";
|
||||
import { betterAuth } from "better-auth";
|
||||
import { github } from "better-auth/social-providers";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: {
|
||||
provider: "sqlite",
|
||||
url: "./db.sqlite",
|
||||
},
|
||||
socialProvider: [
|
||||
github({
|
||||
clientId: env.GITHUB_CLIENT_ID,
|
||||
clientSecret: env.GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createAuthClient } from "better-auth/svelte";
|
||||
import { organization } from "better-auth/client";
|
||||
|
||||
export const client = createAuthClient({
|
||||
baseURL: "http://localhost:3000/api/auth",
|
||||
authPlugins: [organization],
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
@@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
import { client } from "$lib/client";
|
||||
|
||||
const session = client.$session;
|
||||
</script>
|
||||
|
||||
<div
|
||||
style="display: flex; min-height: 100vh; align-items: center; justify-content: center;"
|
||||
>
|
||||
<div
|
||||
style="display: flex; flex-direction: column; gap: 10px; border-radius: 10px; border: 1px solid #4B453F; padding: 20px; margin-top: 10px;"
|
||||
>
|
||||
<div>
|
||||
{#if $session}
|
||||
<div>
|
||||
<p>
|
||||
{$session?.user.name}
|
||||
</p>
|
||||
<p>
|
||||
{$session?.user.email}
|
||||
</p>
|
||||
<button
|
||||
on:click={async () => {
|
||||
await client.signOut();
|
||||
}}
|
||||
>
|
||||
Signout
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<button
|
||||
on:click={async () => {
|
||||
await client.signIn.social({
|
||||
provider: "github",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Continue with github
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
</style>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,18 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
});
|
||||
@@ -29,6 +29,10 @@
|
||||
"./solid": "./dist/solid.js",
|
||||
"./vue": "./dist/vue.js",
|
||||
"./plugins": "./dist/plugins.js",
|
||||
"./svelte-kit": "./dist/svelte-kit.js",
|
||||
"./solid-start": "./dist/solid-start.js",
|
||||
"./svelte": "./dist/svelte.js",
|
||||
"./next-js": "./dist/next-js.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -42,6 +46,7 @@
|
||||
"hono": "^4.5.4",
|
||||
"listhen": "^1.7.2",
|
||||
"react": "^18.3.1",
|
||||
"solid-js": "^1.8.18",
|
||||
"swr": "^2.2.5",
|
||||
"tsup": "^8.2.4",
|
||||
"type-fest": "^4.24.0",
|
||||
|
||||
@@ -37,6 +37,12 @@ export const signInOAuth = createAuthEndpoint(
|
||||
(p) => p.id === c.body.provider,
|
||||
);
|
||||
if (!provider) {
|
||||
c.context.logger.error(
|
||||
"Provider not found. Make sure to add the provider to your auth config",
|
||||
{
|
||||
provider: c.body.provider,
|
||||
},
|
||||
);
|
||||
throw new APIError("NOT_FOUND");
|
||||
}
|
||||
const cookie = c.context.authCookies;
|
||||
|
||||
@@ -31,10 +31,7 @@ export const createAuthClient = <O extends ClientOptions = ClientOptions>(
|
||||
/**
|
||||
* used for plugins only
|
||||
*/
|
||||
const $baseFetch = createFetch({
|
||||
...options,
|
||||
baseURL: getBaseURL(options?.baseURL).withPath,
|
||||
});
|
||||
const $baseFetch = createFetch();
|
||||
const $fetch = createFetch({
|
||||
method: "GET",
|
||||
...options,
|
||||
|
||||
@@ -15,6 +15,7 @@ export const createClientPlugin = <E extends BetterAuthPlugin = never>() => {
|
||||
react?: (useStore: typeof reactStore) => Record<string, any>;
|
||||
vue?: (useStore: typeof vueStore) => Record<string, any>;
|
||||
preact?: (useStore: typeof preactStore) => Record<string, any>;
|
||||
svelte?: () => Record<string, any>;
|
||||
},
|
||||
>(
|
||||
$fn: ($fetch: BetterFetch) => {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { ClientOptions } from "./type";
|
||||
import { createAuthClient as createClient } from "./base";
|
||||
import { useStore } from "@nanostores/solid";
|
||||
import type * as SolidJS from "solid-js"; //to fix ts error: This is likely not portable. A type annotation is necessary.
|
||||
export const createAuthClient = <Option extends ClientOptions>(
|
||||
options?: Option,
|
||||
) => {
|
||||
const client = createClient(options);
|
||||
|
||||
function useSession() {
|
||||
return useStore(client.$atoms.$session);
|
||||
}
|
||||
const obj = Object.assign(client, {
|
||||
useSession,
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { UnionToIntersection } from "../types/helper";
|
||||
import { createAuthClient as createClient } from "./base";
|
||||
import type { AuthPlugin, ClientOptions } from "./type";
|
||||
|
||||
export const createAuthClient = <Option extends ClientOptions>(
|
||||
options?: Option,
|
||||
) => {
|
||||
const client = createClient(options);
|
||||
const signals = options?.authPlugins?.reduce(
|
||||
(acc, plugin) => {
|
||||
return {
|
||||
...acc,
|
||||
...(plugin(client.$fetch).integrations?.svelte?.() || {}),
|
||||
};
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
) as Option["authPlugins"] extends Array<infer Pl>
|
||||
? Pl extends AuthPlugin
|
||||
? UnionToIntersection<
|
||||
ReturnType<Pl>["integrations"] extends
|
||||
| {
|
||||
svelte?: () => infer R;
|
||||
}
|
||||
| undefined
|
||||
? R
|
||||
: {
|
||||
test1: ReturnType<Pl>["integrations"];
|
||||
}
|
||||
>
|
||||
: {}
|
||||
: {};
|
||||
const obj = Object.assign(client, {
|
||||
...signals,
|
||||
$session: client.$atoms.$session,
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
@@ -32,6 +32,7 @@ export type AuthPlugin = ($fetch: BetterFetch) => {
|
||||
react?: (useStore: typeof reactStore) => Record<string, any>;
|
||||
vue?: (useStore: typeof vueStore) => Record<string, any>;
|
||||
preact?: (useStore: typeof preactStore) => Record<string, any>;
|
||||
svelte?: () => Record<string, any>;
|
||||
};
|
||||
pathMethods?: Record<string, "POST" | "GET">;
|
||||
fetchPlugins?: BetterFetchPlugin[];
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { Auth } from "../auth";
|
||||
|
||||
export function toNextJsHandler(auth: Auth | Auth["handler"]) {
|
||||
const handler = async (request: Request) => {
|
||||
return "handler" in auth ? auth.handler(request) : auth(request);
|
||||
};
|
||||
return {
|
||||
GET: handler,
|
||||
POST: handler,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { Auth } from "../auth";
|
||||
|
||||
export function toSolidStartHandler(auth: Auth | Auth["handler"]) {
|
||||
const handler = async (event: {
|
||||
request: Request;
|
||||
}) => {
|
||||
return "handler" in auth
|
||||
? auth.handler(event.request)
|
||||
: auth(event.request);
|
||||
};
|
||||
return {
|
||||
GET: handler,
|
||||
POST: handler,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//@ts-expect-error
|
||||
import { building } from "$app/environment";
|
||||
import type { Auth } from "../auth";
|
||||
import type { BetterAuthOptions } from "../types";
|
||||
|
||||
export const toSvelteKitHandler = (auth: Auth) => {
|
||||
return (event: { request: Request }) => auth.handler(event.request);
|
||||
};
|
||||
|
||||
export const svelteKitHandler = ({
|
||||
auth,
|
||||
event,
|
||||
resolve,
|
||||
}: {
|
||||
auth: Auth;
|
||||
event: { request: Request; url: URL };
|
||||
resolve: (event: any) => any;
|
||||
}) => {
|
||||
if (building) {
|
||||
return resolve(event);
|
||||
}
|
||||
const { request, url } = event;
|
||||
if (isAuthPath(url.toString(), auth.options)) {
|
||||
console.log("here");
|
||||
return auth.handler(request);
|
||||
}
|
||||
return resolve(event);
|
||||
};
|
||||
|
||||
export function isAuthPath(url: string, options: BetterAuthOptions) {
|
||||
const _url = new URL(url);
|
||||
const baseURL = new URL(options.baseURL || _url.origin);
|
||||
const basePath = options.basePath || "/api/auth";
|
||||
if (_url.origin !== baseURL.origin) return false;
|
||||
if (!_url.pathname.startsWith(basePath)) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -1 +1,147 @@
|
||||
import { atom, computed, task } from "nanostores";
|
||||
import type {
|
||||
Invitation,
|
||||
Member,
|
||||
Organization,
|
||||
} from "../../plugins/organization/schema";
|
||||
import type { Prettify } from "../../types/helper";
|
||||
import type { organization as org } from "../../plugins";
|
||||
import { createClientPlugin } from "../../client/create-client-plugin";
|
||||
|
||||
export const organization = createClientPlugin<ReturnType<typeof org>>()(
|
||||
($fetch) => {
|
||||
const activeOrgId = atom<string | null>(null);
|
||||
const $listOrg = atom<boolean>(false);
|
||||
const $activeOrgSignal = atom<boolean>(false);
|
||||
const $activeOrganization = computed([activeOrgId, $activeOrgSignal], () =>
|
||||
task(async () => {
|
||||
if (!activeOrgId.get()) {
|
||||
return null;
|
||||
}
|
||||
const organization = await $fetch<
|
||||
Prettify<
|
||||
Organization & {
|
||||
members: Member[];
|
||||
invitations: Invitation[];
|
||||
}
|
||||
>
|
||||
>("/organization/set-active", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: {
|
||||
orgId: activeOrgId.get(),
|
||||
},
|
||||
});
|
||||
return organization.data;
|
||||
}),
|
||||
);
|
||||
|
||||
const $listOrganizations = computed($listOrg, () =>
|
||||
task(async () => {
|
||||
const organizations = await $fetch<Organization[]>(
|
||||
"/organization/list",
|
||||
{
|
||||
method: "GET",
|
||||
},
|
||||
);
|
||||
return organizations.data;
|
||||
}),
|
||||
);
|
||||
|
||||
const $activeInvitationId = atom<string | null>(null);
|
||||
const $invitation = computed($activeInvitationId, () =>
|
||||
task(async () => {
|
||||
if (!$activeInvitationId.get()) {
|
||||
return {
|
||||
error: {
|
||||
message: "No invitation found",
|
||||
status: 400,
|
||||
data: null,
|
||||
},
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
const res = await $fetch<
|
||||
Prettify<
|
||||
Invitation & {
|
||||
organizationName: string;
|
||||
organizationSlug: string;
|
||||
inviterEmail: string;
|
||||
inviterName: string;
|
||||
}
|
||||
>
|
||||
>("/organization/get-active-invitation", {
|
||||
method: "GET",
|
||||
query: {
|
||||
id: $activeInvitationId.get(),
|
||||
},
|
||||
credentials: "include",
|
||||
});
|
||||
return res;
|
||||
}),
|
||||
);
|
||||
return {
|
||||
id: "organization",
|
||||
actions: {
|
||||
setActiveOrganization(orgId: string | null) {
|
||||
activeOrgId.set(orgId);
|
||||
},
|
||||
setInvitationId: (id: string | null) => {
|
||||
$activeInvitationId.set(id);
|
||||
},
|
||||
},
|
||||
integrations: {
|
||||
react(useStore) {
|
||||
return {
|
||||
useActiveOrganization() {
|
||||
return useStore($activeOrganization);
|
||||
},
|
||||
useListOrganization() {
|
||||
return useStore($listOrganizations);
|
||||
},
|
||||
useInvitation() {
|
||||
return useStore($invitation);
|
||||
},
|
||||
};
|
||||
},
|
||||
vue(useStore) {
|
||||
return {
|
||||
useActiveOrganization() {
|
||||
return useStore($activeOrganization);
|
||||
},
|
||||
useListOrganization() {
|
||||
return useStore($listOrganizations);
|
||||
},
|
||||
useInvitation() {
|
||||
return useStore($invitation);
|
||||
},
|
||||
};
|
||||
},
|
||||
preact(useStore) {
|
||||
return {
|
||||
useActiveOrganization() {
|
||||
return useStore($activeOrganization);
|
||||
},
|
||||
useListOrganization() {
|
||||
return useStore($listOrganizations);
|
||||
},
|
||||
useInvitation() {
|
||||
return useStore($invitation);
|
||||
},
|
||||
};
|
||||
},
|
||||
svelte() {
|
||||
return {
|
||||
$activeOrganization,
|
||||
$listOrganizations,
|
||||
$invitation,
|
||||
};
|
||||
},
|
||||
},
|
||||
signals: {
|
||||
$listOrg,
|
||||
$activeOrgSignal,
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
@@ -29,19 +29,21 @@ export function getBaseURL(url?: string, path?: string) {
|
||||
if (url) {
|
||||
return withPath(url, path);
|
||||
}
|
||||
const env = typeof process !== "undefined" ? process.env : import.meta.env;
|
||||
const fromEnv =
|
||||
process.env.BETTER_AUTH_URL ||
|
||||
process.env.AUTH_URL ||
|
||||
process.env.NEXT_PUBLIC_AUTH_URL ||
|
||||
process.env.NEXT_PUBLIC_BETTER_AUTH_URL;
|
||||
env.BETTER_AUTH_URL ||
|
||||
env.AUTH_URL ||
|
||||
env.NEXT_PUBLIC_AUTH_URL ||
|
||||
env.NEXT_PUBLIC_BETTER_AUTH_URL ||
|
||||
env.PUBLIC_AUTH_URL ||
|
||||
env.PUBLIC_BETTER_AUTH_URL;
|
||||
if (fromEnv) {
|
||||
return withPath(fromEnv, path);
|
||||
}
|
||||
console.log(process.env);
|
||||
if (
|
||||
!fromEnv &&
|
||||
(process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test")
|
||||
) {
|
||||
|
||||
const isDev =
|
||||
!fromEnv && (env.NODE_ENV === "development" || env.NODE_ENV === "test");
|
||||
if (isDev) {
|
||||
return {
|
||||
baseURL: "http://localhost:3000",
|
||||
withPath: "http://localhost:3000/api/auth",
|
||||
|
||||
@@ -12,6 +12,11 @@ export default defineConfig({
|
||||
vue: "./src/client/vue.ts",
|
||||
plugins: "./src/plugins/index.ts",
|
||||
"client/plugins": "./src/client/plugins.ts",
|
||||
"svelte-kit": "./src/integrations/svelte-kit.ts",
|
||||
svelte: "./src/client/svelte.ts",
|
||||
solid: "./src/client/solid.ts",
|
||||
"solid-start": "./src/integrations/solid-start.ts",
|
||||
"next-js": "./src/integrations/next-js.ts",
|
||||
},
|
||||
splitting: false,
|
||||
sourcemap: true,
|
||||
|
||||
Generated
+3032
-25
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user