feat: better-auth, simpler shadcn theme integration
This commit is contained in:
parent
6d592ad48a
commit
7a36d530a0
20 changed files with 4128 additions and 19 deletions
17
README.md
17
README.md
|
|
@ -133,21 +133,14 @@ self-hosted-convex|010...
|
||||||
|
|
||||||
### Frontend setup
|
### Frontend setup
|
||||||
|
|
||||||
1. Time to pick a theme! Go to [shadcn/create](https://ui.shadcn.com/create), create a theme, and simply use the received command to init this theme in Your project!
|
Time to pick a theme! Go to [shadcn/create](https://ui.shadcn.com/create), create a theme, and simply use the received command to init this theme in Your project!
|
||||||
|
|
||||||
2. Replace `aliases` section in `components.json`.
|
### Better Auth
|
||||||
|
|
||||||
```
|
This project utilizes `BetterAuth`. To set it up:
|
||||||
"aliases": {
|
|
||||||
"components": "@/src/components",
|
|
||||||
"utils": "@/src/lib/utils",
|
|
||||||
"ui": "@/src/components/shadcn",
|
|
||||||
"lib": "@/src/lib",
|
|
||||||
"hooks": "@/src/hooks"
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
Move the folders accordingly. Make sure to also update front-end imports, since those changed too.
|
1. `pnpm dlx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)`
|
||||||
|
2. `pnpm dlx convex env set SITE_URL=http://localhost:3000`
|
||||||
|
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
|
|
|
||||||
980
convex/_generated/api.d.ts
vendored
980
convex/_generated/api.d.ts
vendored
|
|
@ -8,7 +8,9 @@
|
||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type * as auth from "../auth.js";
|
||||||
import type * as hello from "../hello.js";
|
import type * as hello from "../hello.js";
|
||||||
|
import type * as http from "../http.js";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiFromModules,
|
ApiFromModules,
|
||||||
|
|
@ -17,7 +19,9 @@ import type {
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
|
|
||||||
declare const fullApi: ApiFromModules<{
|
declare const fullApi: ApiFromModules<{
|
||||||
|
auth: typeof auth;
|
||||||
hello: typeof hello;
|
hello: typeof hello;
|
||||||
|
http: typeof http;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -46,4 +50,978 @@ export declare const internal: FilterApi<
|
||||||
FunctionReference<any, "internal">
|
FunctionReference<any, "internal">
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export declare const components: {};
|
export declare const components: {
|
||||||
|
betterAuth: {
|
||||||
|
adapter: {
|
||||||
|
create: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
| {
|
||||||
|
data: {
|
||||||
|
createdAt: number;
|
||||||
|
email: string;
|
||||||
|
emailVerified: boolean;
|
||||||
|
image?: null | string;
|
||||||
|
name: string;
|
||||||
|
updatedAt: number;
|
||||||
|
userId?: null | string;
|
||||||
|
};
|
||||||
|
model: "user";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: {
|
||||||
|
createdAt: number;
|
||||||
|
expiresAt: number;
|
||||||
|
ipAddress?: null | string;
|
||||||
|
token: string;
|
||||||
|
updatedAt: number;
|
||||||
|
userAgent?: null | string;
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
|
model: "session";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: {
|
||||||
|
accessToken?: null | string;
|
||||||
|
accessTokenExpiresAt?: null | number;
|
||||||
|
accountId: string;
|
||||||
|
createdAt: number;
|
||||||
|
idToken?: null | string;
|
||||||
|
password?: null | string;
|
||||||
|
providerId: string;
|
||||||
|
refreshToken?: null | string;
|
||||||
|
refreshTokenExpiresAt?: null | number;
|
||||||
|
scope?: null | string;
|
||||||
|
updatedAt: number;
|
||||||
|
userId: string;
|
||||||
|
};
|
||||||
|
model: "account";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: {
|
||||||
|
createdAt: number;
|
||||||
|
expiresAt: number;
|
||||||
|
identifier: string;
|
||||||
|
updatedAt: number;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
model: "verification";
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
data: {
|
||||||
|
createdAt: number;
|
||||||
|
expiresAt?: null | number;
|
||||||
|
privateKey: string;
|
||||||
|
publicKey: string;
|
||||||
|
};
|
||||||
|
model: "jwks";
|
||||||
|
};
|
||||||
|
onCreateHandle?: string;
|
||||||
|
select?: Array<string>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
deleteMany: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
| {
|
||||||
|
model: "user";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "name"
|
||||||
|
| "email"
|
||||||
|
| "emailVerified"
|
||||||
|
| "image"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "session";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "expiresAt"
|
||||||
|
| "token"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "ipAddress"
|
||||||
|
| "userAgent"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "account";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "accountId"
|
||||||
|
| "providerId"
|
||||||
|
| "userId"
|
||||||
|
| "accessToken"
|
||||||
|
| "refreshToken"
|
||||||
|
| "idToken"
|
||||||
|
| "accessTokenExpiresAt"
|
||||||
|
| "refreshTokenExpiresAt"
|
||||||
|
| "scope"
|
||||||
|
| "password"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "verification";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "identifier"
|
||||||
|
| "value"
|
||||||
|
| "expiresAt"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "jwks";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "publicKey"
|
||||||
|
| "privateKey"
|
||||||
|
| "createdAt"
|
||||||
|
| "expiresAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onDeleteHandle?: string;
|
||||||
|
paginationOpts: {
|
||||||
|
cursor: string | null;
|
||||||
|
endCursor?: string | null;
|
||||||
|
id?: number;
|
||||||
|
maximumBytesRead?: number;
|
||||||
|
maximumRowsRead?: number;
|
||||||
|
numItems: number;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
deleteOne: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
| {
|
||||||
|
model: "user";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "name"
|
||||||
|
| "email"
|
||||||
|
| "emailVerified"
|
||||||
|
| "image"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "session";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "expiresAt"
|
||||||
|
| "token"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "ipAddress"
|
||||||
|
| "userAgent"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "account";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "accountId"
|
||||||
|
| "providerId"
|
||||||
|
| "userId"
|
||||||
|
| "accessToken"
|
||||||
|
| "refreshToken"
|
||||||
|
| "idToken"
|
||||||
|
| "accessTokenExpiresAt"
|
||||||
|
| "refreshTokenExpiresAt"
|
||||||
|
| "scope"
|
||||||
|
| "password"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "verification";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "identifier"
|
||||||
|
| "value"
|
||||||
|
| "expiresAt"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "jwks";
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "publicKey"
|
||||||
|
| "privateKey"
|
||||||
|
| "createdAt"
|
||||||
|
| "expiresAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onDeleteHandle?: string;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
findMany: FunctionReference<
|
||||||
|
"query",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
join?: any;
|
||||||
|
limit?: number;
|
||||||
|
model: "user" | "session" | "account" | "verification" | "jwks";
|
||||||
|
offset?: number;
|
||||||
|
paginationOpts: {
|
||||||
|
cursor: string | null;
|
||||||
|
endCursor?: string | null;
|
||||||
|
id?: number;
|
||||||
|
maximumBytesRead?: number;
|
||||||
|
maximumRowsRead?: number;
|
||||||
|
numItems: number;
|
||||||
|
};
|
||||||
|
select?: Array<string>;
|
||||||
|
sortBy?: { direction: "asc" | "desc"; field: string };
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: string;
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
findOne: FunctionReference<
|
||||||
|
"query",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
join?: any;
|
||||||
|
model: "user" | "session" | "account" | "verification" | "jwks";
|
||||||
|
select?: Array<string>;
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field: string;
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
updateMany: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
| {
|
||||||
|
model: "user";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
email?: string;
|
||||||
|
emailVerified?: boolean;
|
||||||
|
image?: null | string;
|
||||||
|
name?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userId?: null | string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "name"
|
||||||
|
| "email"
|
||||||
|
| "emailVerified"
|
||||||
|
| "image"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "session";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: number;
|
||||||
|
ipAddress?: null | string;
|
||||||
|
token?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userAgent?: null | string;
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "expiresAt"
|
||||||
|
| "token"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "ipAddress"
|
||||||
|
| "userAgent"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "account";
|
||||||
|
update: {
|
||||||
|
accessToken?: null | string;
|
||||||
|
accessTokenExpiresAt?: null | number;
|
||||||
|
accountId?: string;
|
||||||
|
createdAt?: number;
|
||||||
|
idToken?: null | string;
|
||||||
|
password?: null | string;
|
||||||
|
providerId?: string;
|
||||||
|
refreshToken?: null | string;
|
||||||
|
refreshTokenExpiresAt?: null | number;
|
||||||
|
scope?: null | string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "accountId"
|
||||||
|
| "providerId"
|
||||||
|
| "userId"
|
||||||
|
| "accessToken"
|
||||||
|
| "refreshToken"
|
||||||
|
| "idToken"
|
||||||
|
| "accessTokenExpiresAt"
|
||||||
|
| "refreshTokenExpiresAt"
|
||||||
|
| "scope"
|
||||||
|
| "password"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "verification";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: number;
|
||||||
|
identifier?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "identifier"
|
||||||
|
| "value"
|
||||||
|
| "expiresAt"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "jwks";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: null | number;
|
||||||
|
privateKey?: string;
|
||||||
|
publicKey?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "publicKey"
|
||||||
|
| "privateKey"
|
||||||
|
| "createdAt"
|
||||||
|
| "expiresAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onUpdateHandle?: string;
|
||||||
|
paginationOpts: {
|
||||||
|
cursor: string | null;
|
||||||
|
endCursor?: string | null;
|
||||||
|
id?: number;
|
||||||
|
maximumBytesRead?: number;
|
||||||
|
maximumRowsRead?: number;
|
||||||
|
numItems: number;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
updateOne: FunctionReference<
|
||||||
|
"mutation",
|
||||||
|
"internal",
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
| {
|
||||||
|
model: "user";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
email?: string;
|
||||||
|
emailVerified?: boolean;
|
||||||
|
image?: null | string;
|
||||||
|
name?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userId?: null | string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "name"
|
||||||
|
| "email"
|
||||||
|
| "emailVerified"
|
||||||
|
| "image"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "session";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: number;
|
||||||
|
ipAddress?: null | string;
|
||||||
|
token?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userAgent?: null | string;
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "expiresAt"
|
||||||
|
| "token"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "ipAddress"
|
||||||
|
| "userAgent"
|
||||||
|
| "userId"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "account";
|
||||||
|
update: {
|
||||||
|
accessToken?: null | string;
|
||||||
|
accessTokenExpiresAt?: null | number;
|
||||||
|
accountId?: string;
|
||||||
|
createdAt?: number;
|
||||||
|
idToken?: null | string;
|
||||||
|
password?: null | string;
|
||||||
|
providerId?: string;
|
||||||
|
refreshToken?: null | string;
|
||||||
|
refreshTokenExpiresAt?: null | number;
|
||||||
|
scope?: null | string;
|
||||||
|
updatedAt?: number;
|
||||||
|
userId?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "accountId"
|
||||||
|
| "providerId"
|
||||||
|
| "userId"
|
||||||
|
| "accessToken"
|
||||||
|
| "refreshToken"
|
||||||
|
| "idToken"
|
||||||
|
| "accessTokenExpiresAt"
|
||||||
|
| "refreshTokenExpiresAt"
|
||||||
|
| "scope"
|
||||||
|
| "password"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "verification";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: number;
|
||||||
|
identifier?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "identifier"
|
||||||
|
| "value"
|
||||||
|
| "expiresAt"
|
||||||
|
| "createdAt"
|
||||||
|
| "updatedAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
model: "jwks";
|
||||||
|
update: {
|
||||||
|
createdAt?: number;
|
||||||
|
expiresAt?: null | number;
|
||||||
|
privateKey?: string;
|
||||||
|
publicKey?: string;
|
||||||
|
};
|
||||||
|
where?: Array<{
|
||||||
|
connector?: "AND" | "OR";
|
||||||
|
field:
|
||||||
|
| "publicKey"
|
||||||
|
| "privateKey"
|
||||||
|
| "createdAt"
|
||||||
|
| "expiresAt"
|
||||||
|
| "_id";
|
||||||
|
operator?:
|
||||||
|
| "lt"
|
||||||
|
| "lte"
|
||||||
|
| "gt"
|
||||||
|
| "gte"
|
||||||
|
| "eq"
|
||||||
|
| "in"
|
||||||
|
| "not_in"
|
||||||
|
| "ne"
|
||||||
|
| "contains"
|
||||||
|
| "starts_with"
|
||||||
|
| "ends_with";
|
||||||
|
value:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string>
|
||||||
|
| Array<number>
|
||||||
|
| null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
onUpdateHandle?: string;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
6
convex/auth.config.ts
Normal file
6
convex/auth.config.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { getAuthConfigProvider } from '@convex-dev/better-auth/auth-config';
|
||||||
|
import type { AuthConfig } from 'convex/server';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
providers: [getAuthConfigProvider()],
|
||||||
|
} satisfies AuthConfig;
|
||||||
44
convex/auth.ts
Normal file
44
convex/auth.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { createClient, type GenericCtx } from '@convex-dev/better-auth';
|
||||||
|
import { convex } from '@convex-dev/better-auth/plugins';
|
||||||
|
import { components } from './_generated/api';
|
||||||
|
import { DataModel } from './_generated/dataModel';
|
||||||
|
import { query } from './_generated/server';
|
||||||
|
import { betterAuth, type BetterAuthOptions } from 'better-auth/minimal';
|
||||||
|
import authConfig from './auth.config';
|
||||||
|
import authSchema from './betterAuth/schema';
|
||||||
|
|
||||||
|
const siteUrl = process.env.SITE_URL!;
|
||||||
|
|
||||||
|
export const authComponent = createClient<DataModel, typeof authSchema>(
|
||||||
|
components.betterAuth,
|
||||||
|
{
|
||||||
|
local: {
|
||||||
|
schema: authSchema,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const createAuthOptions = (ctx: GenericCtx<DataModel>): BetterAuthOptions => {
|
||||||
|
return {
|
||||||
|
baseURL: siteUrl,
|
||||||
|
database: authComponent.adapter(ctx),
|
||||||
|
emailAndPassword: {
|
||||||
|
enabled: true,
|
||||||
|
requireEmailVerification: false,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
convex({ authConfig }),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createAuth = (ctx: GenericCtx<DataModel>) => {
|
||||||
|
return betterAuth(createAuthOptions(ctx));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCurrentUser = query({
|
||||||
|
args: {},
|
||||||
|
handler: async (ctx) => {
|
||||||
|
return authComponent.getAuthUser(ctx);
|
||||||
|
},
|
||||||
|
});
|
||||||
52
convex/betterAuth/_generated/api.ts
Normal file
52
convex/betterAuth/_generated/api.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated `api` utility.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type * as adapter from "../adapter.js";
|
||||||
|
import type * as auth from "../auth.js";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ApiFromModules,
|
||||||
|
FilterApi,
|
||||||
|
FunctionReference,
|
||||||
|
} from "convex/server";
|
||||||
|
import { anyApi, componentsGeneric } from "convex/server";
|
||||||
|
|
||||||
|
const fullApi: ApiFromModules<{
|
||||||
|
adapter: typeof adapter;
|
||||||
|
auth: typeof auth;
|
||||||
|
}> = anyApi as any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's public API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = api.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const api: FilterApi<
|
||||||
|
typeof fullApi,
|
||||||
|
FunctionReference<any, "public">
|
||||||
|
> = anyApi as any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's internal API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = internal.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const internal: FilterApi<
|
||||||
|
typeof fullApi,
|
||||||
|
FunctionReference<any, "internal">
|
||||||
|
> = anyApi as any;
|
||||||
|
|
||||||
|
export const components = componentsGeneric() as unknown as {};
|
||||||
1004
convex/betterAuth/_generated/component.ts
Normal file
1004
convex/betterAuth/_generated/component.ts
Normal file
File diff suppressed because it is too large
Load diff
60
convex/betterAuth/_generated/dataModel.ts
Normal file
60
convex/betterAuth/_generated/dataModel.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated data model types.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
DataModelFromSchemaDefinition,
|
||||||
|
DocumentByName,
|
||||||
|
TableNamesInDataModel,
|
||||||
|
SystemTableNames,
|
||||||
|
} from "convex/server";
|
||||||
|
import type { GenericId } from "convex/values";
|
||||||
|
import schema from "../schema.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of all of your Convex tables.
|
||||||
|
*/
|
||||||
|
export type TableNames = TableNamesInDataModel<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of a document stored in Convex.
|
||||||
|
*
|
||||||
|
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||||
|
*/
|
||||||
|
export type Doc<TableName extends TableNames> = DocumentByName<
|
||||||
|
DataModel,
|
||||||
|
TableName
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An identifier for a document in Convex.
|
||||||
|
*
|
||||||
|
* Convex documents are uniquely identified by their `Id`, which is accessible
|
||||||
|
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
|
||||||
|
*
|
||||||
|
* Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.
|
||||||
|
*
|
||||||
|
* IDs are just strings at runtime, but this type can be used to distinguish them from other
|
||||||
|
* strings when type checking.
|
||||||
|
*
|
||||||
|
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||||
|
*/
|
||||||
|
export type Id<TableName extends TableNames | SystemTableNames> =
|
||||||
|
GenericId<TableName>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type describing your Convex data model.
|
||||||
|
*
|
||||||
|
* This type includes information about what tables you have, the type of
|
||||||
|
* documents stored in those tables, and the indexes defined on them.
|
||||||
|
*
|
||||||
|
* This type is used to parameterize methods like `queryGeneric` and
|
||||||
|
* `mutationGeneric` to make them type-safe.
|
||||||
|
*/
|
||||||
|
export type DataModel = DataModelFromSchemaDefinition<typeof schema>;
|
||||||
156
convex/betterAuth/_generated/server.ts
Normal file
156
convex/betterAuth/_generated/server.ts
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Generated utilities for implementing server-side Convex query and mutation functions.
|
||||||
|
*
|
||||||
|
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||||
|
*
|
||||||
|
* To regenerate, run `npx convex dev`.
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ActionBuilder,
|
||||||
|
HttpActionBuilder,
|
||||||
|
MutationBuilder,
|
||||||
|
QueryBuilder,
|
||||||
|
GenericActionCtx,
|
||||||
|
GenericMutationCtx,
|
||||||
|
GenericQueryCtx,
|
||||||
|
GenericDatabaseReader,
|
||||||
|
GenericDatabaseWriter,
|
||||||
|
} from "convex/server";
|
||||||
|
import {
|
||||||
|
actionGeneric,
|
||||||
|
httpActionGeneric,
|
||||||
|
queryGeneric,
|
||||||
|
mutationGeneric,
|
||||||
|
internalActionGeneric,
|
||||||
|
internalMutationGeneric,
|
||||||
|
internalQueryGeneric,
|
||||||
|
} from "convex/server";
|
||||||
|
import type { DataModel } from "./dataModel.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to read your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const query: QueryBuilder<DataModel, "public"> = queryGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a query that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||||
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalQuery: QueryBuilder<DataModel, "internal"> =
|
||||||
|
internalQueryGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const mutation: MutationBuilder<DataModel, "public"> = mutationGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
||||||
|
*
|
||||||
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||||
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalMutation: MutationBuilder<DataModel, "internal"> =
|
||||||
|
internalMutationGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action in this Convex app's public API.
|
||||||
|
*
|
||||||
|
* An action is a function which can execute any JavaScript code, including non-deterministic
|
||||||
|
* code and code with side-effects, like calling third-party services.
|
||||||
|
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
||||||
|
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
||||||
|
*
|
||||||
|
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const action: ActionBuilder<DataModel, "public"> = actionGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an action that is only accessible from other Convex functions (but not from the client).
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||||
|
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
||||||
|
*/
|
||||||
|
export const internalAction: ActionBuilder<DataModel, "internal"> =
|
||||||
|
internalActionGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an HTTP action.
|
||||||
|
*
|
||||||
|
* The wrapped function will be used to respond to HTTP requests received
|
||||||
|
* by a Convex deployment if the requests matches the path and method where
|
||||||
|
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||||
|
* and a Fetch API `Request` object as its second.
|
||||||
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||||
|
*/
|
||||||
|
export const httpAction: HttpActionBuilder = httpActionGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex query functions.
|
||||||
|
*
|
||||||
|
* The query context is passed as the first argument to any Convex query
|
||||||
|
* function run on the server.
|
||||||
|
*
|
||||||
|
* If you're using code generation, use the `QueryCtx` type in `convex/_generated/server.d.ts` instead.
|
||||||
|
*/
|
||||||
|
export type QueryCtx = GenericQueryCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex mutation functions.
|
||||||
|
*
|
||||||
|
* The mutation context is passed as the first argument to any Convex mutation
|
||||||
|
* function run on the server.
|
||||||
|
*
|
||||||
|
* If you're using code generation, use the `MutationCtx` type in `convex/_generated/server.d.ts` instead.
|
||||||
|
*/
|
||||||
|
export type MutationCtx = GenericMutationCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of services for use within Convex action functions.
|
||||||
|
*
|
||||||
|
* The action context is passed as the first argument to any Convex action
|
||||||
|
* function run on the server.
|
||||||
|
*/
|
||||||
|
export type ActionCtx = GenericActionCtx<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to read from the database within Convex query functions.
|
||||||
|
*
|
||||||
|
* The two entry points are {@link DatabaseReader.get}, which fetches a single
|
||||||
|
* document by its {@link Id}, or {@link DatabaseReader.query}, which starts
|
||||||
|
* building a query.
|
||||||
|
*/
|
||||||
|
export type DatabaseReader = GenericDatabaseReader<DataModel>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to read from and write to the database within Convex mutation
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* Convex guarantees that all writes within a single mutation are
|
||||||
|
* executed atomically, so you never have to worry about partial writes leaving
|
||||||
|
* your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)
|
||||||
|
* for the guarantees Convex provides your functions.
|
||||||
|
*/
|
||||||
|
export type DatabaseWriter = GenericDatabaseWriter<DataModel>;
|
||||||
13
convex/betterAuth/adapter.ts
Normal file
13
convex/betterAuth/adapter.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { createApi } from '@convex-dev/better-auth';
|
||||||
|
import { createAuthOptions } from '../auth';
|
||||||
|
import schema from './schema';
|
||||||
|
|
||||||
|
export const {
|
||||||
|
create,
|
||||||
|
findOne,
|
||||||
|
findMany,
|
||||||
|
updateOne,
|
||||||
|
updateMany,
|
||||||
|
deleteOne,
|
||||||
|
deleteMany,
|
||||||
|
} = createApi(schema, createAuthOptions);
|
||||||
3
convex/betterAuth/auth.ts
Normal file
3
convex/betterAuth/auth.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { createAuth } from '../auth';
|
||||||
|
|
||||||
|
export const auth = createAuth({} as any);
|
||||||
5
convex/betterAuth/convex.config.ts
Normal file
5
convex/betterAuth/convex.config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { defineComponent } from 'convex/server';
|
||||||
|
|
||||||
|
const component = defineComponent('betterAuth');
|
||||||
|
|
||||||
|
export default component;
|
||||||
77
convex/betterAuth/schema.ts
Normal file
77
convex/betterAuth/schema.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* This file is auto-generated. Do not edit this file manually.
|
||||||
|
* To regenerate the schema, run:
|
||||||
|
* `npx @better-auth/cli generate --output undefined -y`
|
||||||
|
*
|
||||||
|
* To customize the schema, generate to an alternate file and import
|
||||||
|
* the table definitions to your schema file. See
|
||||||
|
* https://labs.convex.dev/better-auth/features/local-install#adding-custom-indexes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { defineSchema, defineTable } from "convex/server";
|
||||||
|
import { v } from "convex/values";
|
||||||
|
|
||||||
|
export const tables = {
|
||||||
|
user: defineTable({
|
||||||
|
name: v.string(),
|
||||||
|
email: v.string(),
|
||||||
|
emailVerified: v.boolean(),
|
||||||
|
image: v.optional(v.union(v.null(), v.string())),
|
||||||
|
createdAt: v.number(),
|
||||||
|
updatedAt: v.number(),
|
||||||
|
userId: v.optional(v.union(v.null(), v.string())),
|
||||||
|
})
|
||||||
|
.index("email_name", ["email","name"])
|
||||||
|
.index("name", ["name"])
|
||||||
|
.index("userId", ["userId"]),
|
||||||
|
session: defineTable({
|
||||||
|
expiresAt: v.number(),
|
||||||
|
token: v.string(),
|
||||||
|
createdAt: v.number(),
|
||||||
|
updatedAt: v.number(),
|
||||||
|
ipAddress: v.optional(v.union(v.null(), v.string())),
|
||||||
|
userAgent: v.optional(v.union(v.null(), v.string())),
|
||||||
|
userId: v.string(),
|
||||||
|
})
|
||||||
|
.index("expiresAt", ["expiresAt"])
|
||||||
|
.index("expiresAt_userId", ["expiresAt","userId"])
|
||||||
|
.index("token", ["token"])
|
||||||
|
.index("userId", ["userId"]),
|
||||||
|
account: defineTable({
|
||||||
|
accountId: v.string(),
|
||||||
|
providerId: v.string(),
|
||||||
|
userId: v.string(),
|
||||||
|
accessToken: v.optional(v.union(v.null(), v.string())),
|
||||||
|
refreshToken: v.optional(v.union(v.null(), v.string())),
|
||||||
|
idToken: v.optional(v.union(v.null(), v.string())),
|
||||||
|
accessTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
|
||||||
|
refreshTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
|
||||||
|
scope: v.optional(v.union(v.null(), v.string())),
|
||||||
|
password: v.optional(v.union(v.null(), v.string())),
|
||||||
|
createdAt: v.number(),
|
||||||
|
updatedAt: v.number(),
|
||||||
|
})
|
||||||
|
.index("accountId", ["accountId"])
|
||||||
|
.index("accountId_providerId", ["accountId","providerId"])
|
||||||
|
.index("providerId_userId", ["providerId","userId"])
|
||||||
|
.index("userId", ["userId"]),
|
||||||
|
verification: defineTable({
|
||||||
|
identifier: v.string(),
|
||||||
|
value: v.string(),
|
||||||
|
expiresAt: v.number(),
|
||||||
|
createdAt: v.number(),
|
||||||
|
updatedAt: v.number(),
|
||||||
|
})
|
||||||
|
.index("expiresAt", ["expiresAt"])
|
||||||
|
.index("identifier", ["identifier"]),
|
||||||
|
jwks: defineTable({
|
||||||
|
publicKey: v.string(),
|
||||||
|
privateKey: v.string(),
|
||||||
|
createdAt: v.number(),
|
||||||
|
expiresAt: v.optional(v.union(v.null(), v.number())),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema = defineSchema(tables);
|
||||||
|
|
||||||
|
export default schema;
|
||||||
8
convex/convex.config.ts
Normal file
8
convex/convex.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { defineApp } from 'convex/server';
|
||||||
|
import betterAuth from './betterAuth/convex.config';
|
||||||
|
|
||||||
|
const app = defineApp();
|
||||||
|
|
||||||
|
app.use(betterAuth);
|
||||||
|
|
||||||
|
export default app;
|
||||||
8
convex/http.ts
Normal file
8
convex/http.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { httpRouter } from 'convex/server';
|
||||||
|
import { authComponent, createAuth } from './auth';
|
||||||
|
|
||||||
|
const http = httpRouter();
|
||||||
|
|
||||||
|
authComponent.registerRoutes(http, createAuth);
|
||||||
|
|
||||||
|
export default http;
|
||||||
|
|
@ -3,12 +3,14 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev --webpack",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@convex-dev/better-auth": "^0.11.4",
|
||||||
|
"better-auth": "^1.5.6",
|
||||||
"convex": "^1.34.0",
|
"convex": "^1.34.0",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"next-intl": "^4.8.3",
|
"next-intl": "^4.8.3",
|
||||||
|
|
@ -17,6 +19,7 @@
|
||||||
"react-dom": "19.2.4"
|
"react-dom": "19.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@better-auth/cli": "^1.4.21",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
|
|
|
||||||
1657
pnpm-lock.yaml
1657
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
3
src/app/api/auth/[...all]/route.ts
Normal file
3
src/app/api/auth/[...all]/route.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { handler } from '@/lib/auth-server';
|
||||||
|
|
||||||
|
export const { GET, POST } = handler;
|
||||||
6
src/lib/auth-client.ts
Normal file
6
src/lib/auth-client.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { createAuthClient } from 'better-auth/react';
|
||||||
|
import { convexClient } from '@convex-dev/better-auth/client/plugins';
|
||||||
|
|
||||||
|
export const authClient = createAuthClient({
|
||||||
|
plugins: [convexClient()],
|
||||||
|
});
|
||||||
14
src/lib/auth-server.ts
Normal file
14
src/lib/auth-server.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { convexBetterAuthNextJs } from '@convex-dev/better-auth/nextjs';
|
||||||
|
|
||||||
|
export const {
|
||||||
|
handler,
|
||||||
|
preloadAuthQuery,
|
||||||
|
isAuthenticated,
|
||||||
|
getToken,
|
||||||
|
fetchAuthQuery,
|
||||||
|
fetchAuthMutation,
|
||||||
|
fetchAuthAction,
|
||||||
|
} = convexBetterAuthNextJs({
|
||||||
|
convexUrl: process.env.NEXT_PUBLIC_CONVEX_URL!,
|
||||||
|
convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_URL!,
|
||||||
|
});
|
||||||
29
src/lib/routes.ts
Normal file
29
src/lib/routes.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
export const routes = {
|
||||||
|
home: '/',
|
||||||
|
signIn: '/sign-in',
|
||||||
|
signUp: '/sign-up',
|
||||||
|
dashboard: '/dashboard',
|
||||||
|
settings: '/settings',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const publicRoutes = [
|
||||||
|
routes.home,
|
||||||
|
routes.signIn,
|
||||||
|
routes.signUp,
|
||||||
|
'/pricing',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const authRoutes = [routes.signIn, routes.signUp] as const;
|
||||||
|
|
||||||
|
export function matchesRoute(pathname: string, route: string) {
|
||||||
|
if (route === '/') return pathname === '/';
|
||||||
|
return pathname === route || pathname.startsWith(`${route}/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPublicRoute(pathname: string) {
|
||||||
|
return publicRoutes.some((route) => matchesRoute(pathname, route));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAuthRoute(pathname: string) {
|
||||||
|
return authRoutes.some((route) => matchesRoute(pathname, route));
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue