From bf2087cded0dcadd7442a5f74d3ec2ba5e9c520c Mon Sep 17 00:00:00 2001 From: kenneth Date: Sun, 5 Oct 2025 23:25:20 +0000 Subject: [PATCH] refactor: migrate betterauth to local install also added a login page Co-authored-by: Ona --- packages/convex/_generated/api.d.ts | 2360 +---------------- packages/convex/auth.config.ts | 4 +- packages/convex/auth.ts | 31 +- .../convex/betterauth/_generated/api.d.ts | 971 +++++++ packages/convex/betterauth/_generated/api.js | 23 + .../betterauth/_generated/dataModel.d.ts | 60 + .../convex/betterauth/_generated/server.d.ts | 149 ++ .../convex/betterauth/_generated/server.js | 90 + packages/convex/betterauth/adapter.ts | 13 + packages/convex/betterauth/auth.ts | 5 + packages/convex/betterauth/convex.config.ts | 5 + packages/convex/betterauth/schema.ts | 70 + packages/convex/convex.config.ts | 2 +- packages/convex/convex/_generated/api.d.ts | 33 + packages/convex/convex/_generated/api.js | 22 + .../convex/convex/_generated/dataModel.d.ts | 58 + packages/convex/convex/_generated/server.d.ts | 142 + packages/convex/convex/_generated/server.js | 89 + packages/web/src/auth.ts | 6 + packages/web/src/routes/__root.tsx | 4 +- packages/web/src/routes/_authenticated.tsx | 6 +- packages/web/src/routes/login.tsx | 176 +- packages/web/src/routes/sign-up.tsx | 8 +- 23 files changed, 1951 insertions(+), 2376 deletions(-) create mode 100644 packages/convex/betterauth/_generated/api.d.ts create mode 100644 packages/convex/betterauth/_generated/api.js create mode 100644 packages/convex/betterauth/_generated/dataModel.d.ts create mode 100644 packages/convex/betterauth/_generated/server.d.ts create mode 100644 packages/convex/betterauth/_generated/server.js create mode 100644 packages/convex/betterauth/adapter.ts create mode 100644 packages/convex/betterauth/auth.ts create mode 100644 packages/convex/betterauth/convex.config.ts create mode 100644 packages/convex/betterauth/schema.ts create mode 100644 packages/convex/convex/_generated/api.d.ts create mode 100644 packages/convex/convex/_generated/api.js create mode 100644 packages/convex/convex/_generated/dataModel.d.ts create mode 100644 packages/convex/convex/_generated/server.d.ts create mode 100644 packages/convex/convex/_generated/server.js diff --git a/packages/convex/_generated/api.d.ts b/packages/convex/_generated/api.d.ts index b0ba55d..cf0de01 100644 --- a/packages/convex/_generated/api.d.ts +++ b/packages/convex/_generated/api.d.ts @@ -9,6 +9,12 @@ */ import type * as auth from "../auth.js"; +import type * as betterauth__generated_api from "../betterauth/_generated/api.js"; +import type * as betterauth__generated_server from "../betterauth/_generated/server.js"; +import type * as betterauth_adapter from "../betterauth/adapter.js"; +import type * as betterauth_auth from "../betterauth/auth.js"; +import type * as convex__generated_api from "../convex/_generated/api.js"; +import type * as convex__generated_server from "../convex/_generated/server.js"; import type * as files from "../files.js"; import type * as filesystem from "../filesystem.js"; import type * as functions from "../functions.js"; @@ -36,6 +42,12 @@ import type { */ declare const fullApi: ApiFromModules<{ auth: typeof auth; + "betterauth/_generated/api": typeof betterauth__generated_api; + "betterauth/_generated/server": typeof betterauth__generated_server; + "betterauth/adapter": typeof betterauth_adapter; + "betterauth/auth": typeof betterauth_auth; + "convex/_generated/api": typeof convex__generated_api; + "convex/_generated/server": typeof convex__generated_server; files: typeof files; filesystem: typeof filesystem; functions: typeof functions; @@ -69,18 +81,12 @@ export declare const components: { | { data: { createdAt: number; - displayUsername?: null | string; email: string; emailVerified: boolean; image?: null | string; - isAnonymous?: null | boolean; name: string; - phoneNumber?: null | string; - phoneNumberVerified?: null | boolean; - twoFactorEnabled?: null | boolean; updatedAt: number; userId?: null | string; - username?: null | string; }; model: "user"; } @@ -123,126 +129,6 @@ export declare const components: { }; model: "verification"; } - | { - data: { backupCodes: string; secret: string; userId: string }; - model: "twoFactor"; - } - | { - data: { - aaguid?: null | string; - backedUp: boolean; - counter: number; - createdAt?: null | number; - credentialID: string; - deviceType: string; - name?: null | string; - publicKey: string; - transports?: null | string; - userId: string; - }; - model: "passkey"; - } - | { - data: { - clientId?: null | string; - clientSecret?: null | string; - createdAt?: null | number; - disabled?: null | boolean; - icon?: null | string; - metadata?: null | string; - name?: null | string; - redirectURLs?: null | string; - type?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - model: "oauthApplication"; - } - | { - data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; - createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - model: "oauthAccessToken"; - } - | { - data: { - clientId?: null | string; - consentGiven?: null | boolean; - createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - model: "oauthConsent"; - } - | { - data: { - createdAt: number; - name: string; - organizationId: string; - updatedAt?: null | number; - }; - model: "team"; - } - | { - data: { - createdAt?: null | number; - teamId: string; - userId: string; - }; - model: "teamMember"; - } - | { - data: { - createdAt: number; - logo?: null | string; - metadata?: null | string; - name: string; - slug?: null | string; - }; - model: "organization"; - } - | { - data: { - createdAt: number; - organizationId: string; - role: string; - userId: string; - }; - model: "member"; - } - | { - data: { - email: string; - expiresAt: number; - inviterId: string; - organizationId: string; - role?: null | string; - status: string; - teamId?: null | string; - }; - model: "invitation"; - } - | { - data: { - domain: string; - issuer: string; - oidcConfig?: null | string; - organizationId?: null | string; - providerId: string; - samlConfig?: null | string; - userId?: null | string; - }; - model: "ssoProvider"; - } | { data: { createdAt: number; @@ -250,44 +136,6 @@ export declare const components: { publicKey: string; }; model: "jwks"; - } - | { - data: { - cancelAtPeriodEnd?: null | boolean; - periodEnd?: null | number; - periodStart?: null | number; - plan: string; - referenceId: string; - seats?: null | number; - status?: null | string; - stripeCustomerId?: null | string; - stripeSubscriptionId?: null | string; - trialEnd?: null | number; - trialStart?: null | number; - }; - model: "subscription"; - } - | { - data: { - address: string; - chainId: number; - createdAt: number; - isPrimary?: null | boolean; - userId: string; - }; - model: "walletAddress"; - } - | { - data: { - count?: null | number; - key?: null | string; - lastRequest?: null | number; - }; - model: "rateLimit"; - } - | { - data: { count: number; key: string; lastRequest: number }; - model: "ratelimit"; }; onCreateHandle?: string; select?: Array; @@ -310,12 +158,6 @@ export declare const components: { | "image" | "createdAt" | "updatedAt" - | "twoFactorEnabled" - | "isAnonymous" - | "username" - | "displayUsername" - | "phoneNumber" - | "phoneNumberVerified" | "userId" | "id"; operator?: @@ -440,353 +282,6 @@ export declare const components: { | null; }>; } - | { - model: "twoFactor"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "secret" | "backupCodes" | "userId" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "passkey"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "publicKey" - | "userId" - | "credentialID" - | "counter" - | "deviceType" - | "backedUp" - | "transports" - | "createdAt" - | "aaguid" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthApplication"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "icon" - | "metadata" - | "clientId" - | "clientSecret" - | "redirectURLs" - | "type" - | "disabled" - | "userId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthAccessToken"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthConsent"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "consentGiven" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "team"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "organizationId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "teamMember"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "teamId" | "userId" | "createdAt" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "organization"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "slug" - | "logo" - | "createdAt" - | "metadata" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "member"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "userId" - | "role" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "invitation"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "email" - | "role" - | "teamId" - | "status" - | "expiresAt" - | "inviterId" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ssoProvider"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "issuer" - | "oidcConfig" - | "samlConfig" - | "userId" - | "providerId" - | "organizationId" - | "domain" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } | { model: "jwks"; where?: Array<{ @@ -811,124 +306,6 @@ export declare const components: { | Array | null; }>; - } - | { - model: "subscription"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "plan" - | "referenceId" - | "stripeCustomerId" - | "stripeSubscriptionId" - | "status" - | "periodStart" - | "periodEnd" - | "trialStart" - | "trialEnd" - | "cancelAtPeriodEnd" - | "seats" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "walletAddress"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "userId" - | "address" - | "chainId" - | "isPrimary" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "rateLimit"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ratelimit"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; }; onDeleteHandle?: string; paginationOpts: { @@ -958,12 +335,6 @@ export declare const components: { | "image" | "createdAt" | "updatedAt" - | "twoFactorEnabled" - | "isAnonymous" - | "username" - | "displayUsername" - | "phoneNumber" - | "phoneNumberVerified" | "userId" | "id"; operator?: @@ -1088,353 +459,6 @@ export declare const components: { | null; }>; } - | { - model: "twoFactor"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "secret" | "backupCodes" | "userId" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "passkey"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "publicKey" - | "userId" - | "credentialID" - | "counter" - | "deviceType" - | "backedUp" - | "transports" - | "createdAt" - | "aaguid" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthApplication"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "icon" - | "metadata" - | "clientId" - | "clientSecret" - | "redirectURLs" - | "type" - | "disabled" - | "userId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthAccessToken"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthConsent"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "consentGiven" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "team"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "organizationId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "teamMember"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "teamId" | "userId" | "createdAt" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "organization"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "slug" - | "logo" - | "createdAt" - | "metadata" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "member"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "userId" - | "role" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "invitation"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "email" - | "role" - | "teamId" - | "status" - | "expiresAt" - | "inviterId" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ssoProvider"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "issuer" - | "oidcConfig" - | "samlConfig" - | "userId" - | "providerId" - | "organizationId" - | "domain" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } | { model: "jwks"; where?: Array<{ @@ -1459,124 +483,6 @@ export declare const components: { | Array | null; }>; - } - | { - model: "subscription"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "plan" - | "referenceId" - | "stripeCustomerId" - | "stripeSubscriptionId" - | "status" - | "periodStart" - | "periodEnd" - | "trialStart" - | "trialEnd" - | "cancelAtPeriodEnd" - | "seats" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "walletAddress"; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "userId" - | "address" - | "chainId" - | "isPrimary" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "rateLimit"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ratelimit"; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; }; onDeleteHandle?: string; }, @@ -1587,27 +493,7 @@ export declare const components: { "internal", { limit?: number; - model: - | "user" - | "session" - | "account" - | "verification" - | "twoFactor" - | "passkey" - | "oauthApplication" - | "oauthAccessToken" - | "oauthConsent" - | "team" - | "teamMember" - | "organization" - | "member" - | "invitation" - | "ssoProvider" - | "jwks" - | "subscription" - | "walletAddress" - | "rateLimit" - | "ratelimit"; + model: "user" | "session" | "account" | "verification" | "jwks"; offset?: number; paginationOpts: { cursor: string | null; @@ -1647,27 +533,7 @@ export declare const components: { "query", "internal", { - model: - | "user" - | "session" - | "account" - | "verification" - | "twoFactor" - | "passkey" - | "oauthApplication" - | "oauthAccessToken" - | "oauthConsent" - | "team" - | "teamMember" - | "organization" - | "member" - | "invitation" - | "ssoProvider" - | "jwks" - | "subscription" - | "walletAddress" - | "rateLimit" - | "ratelimit"; + model: "user" | "session" | "account" | "verification" | "jwks"; select?: Array; where?: Array<{ connector?: "AND" | "OR"; @@ -1703,18 +569,12 @@ export declare const components: { model: "user"; update: { createdAt?: number; - displayUsername?: null | string; email?: string; emailVerified?: boolean; image?: null | string; - isAnonymous?: null | boolean; name?: string; - phoneNumber?: null | string; - phoneNumberVerified?: null | boolean; - twoFactorEnabled?: null | boolean; updatedAt?: number; userId?: null | string; - username?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; @@ -1725,12 +585,6 @@ export declare const components: { | "image" | "createdAt" | "updatedAt" - | "twoFactorEnabled" - | "isAnonymous" - | "username" - | "displayUsername" - | "phoneNumber" - | "phoneNumberVerified" | "userId" | "id"; operator?: @@ -1885,444 +739,6 @@ export declare const components: { | null; }>; } - | { - model: "twoFactor"; - update: { - backupCodes?: string; - secret?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "secret" | "backupCodes" | "userId" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "passkey"; - update: { - aaguid?: null | string; - backedUp?: boolean; - counter?: number; - createdAt?: null | number; - credentialID?: string; - deviceType?: string; - name?: null | string; - publicKey?: string; - transports?: null | string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "publicKey" - | "userId" - | "credentialID" - | "counter" - | "deviceType" - | "backedUp" - | "transports" - | "createdAt" - | "aaguid" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthApplication"; - update: { - clientId?: null | string; - clientSecret?: null | string; - createdAt?: null | number; - disabled?: null | boolean; - icon?: null | string; - metadata?: null | string; - name?: null | string; - redirectURLs?: null | string; - type?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "icon" - | "metadata" - | "clientId" - | "clientSecret" - | "redirectURLs" - | "type" - | "disabled" - | "userId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthAccessToken"; - update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; - createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthConsent"; - update: { - clientId?: null | string; - consentGiven?: null | boolean; - createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "consentGiven" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "team"; - update: { - createdAt?: number; - name?: string; - organizationId?: string; - updatedAt?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "organizationId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "teamMember"; - update: { - createdAt?: null | number; - teamId?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "teamId" | "userId" | "createdAt" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "organization"; - update: { - createdAt?: number; - logo?: null | string; - metadata?: null | string; - name?: string; - slug?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "slug" - | "logo" - | "createdAt" - | "metadata" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "member"; - update: { - createdAt?: number; - organizationId?: string; - role?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "userId" - | "role" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "invitation"; - update: { - email?: string; - expiresAt?: number; - inviterId?: string; - organizationId?: string; - role?: null | string; - status?: string; - teamId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "email" - | "role" - | "teamId" - | "status" - | "expiresAt" - | "inviterId" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ssoProvider"; - update: { - domain?: string; - issuer?: string; - oidcConfig?: null | string; - organizationId?: null | string; - providerId?: string; - samlConfig?: null | string; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "issuer" - | "oidcConfig" - | "samlConfig" - | "userId" - | "providerId" - | "organizationId" - | "domain" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } | { model: "jwks"; update: { @@ -2352,150 +768,6 @@ export declare const components: { | Array | null; }>; - } - | { - model: "subscription"; - update: { - cancelAtPeriodEnd?: null | boolean; - periodEnd?: null | number; - periodStart?: null | number; - plan?: string; - referenceId?: string; - seats?: null | number; - status?: null | string; - stripeCustomerId?: null | string; - stripeSubscriptionId?: null | string; - trialEnd?: null | number; - trialStart?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "plan" - | "referenceId" - | "stripeCustomerId" - | "stripeSubscriptionId" - | "status" - | "periodStart" - | "periodEnd" - | "trialStart" - | "trialEnd" - | "cancelAtPeriodEnd" - | "seats" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "walletAddress"; - update: { - address?: string; - chainId?: number; - createdAt?: number; - isPrimary?: null | boolean; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "userId" - | "address" - | "chainId" - | "isPrimary" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "rateLimit"; - update: { - count?: null | number; - key?: null | string; - lastRequest?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ratelimit"; - update: { count?: number; key?: string; lastRequest?: number }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; }; onUpdateHandle?: string; paginationOpts: { @@ -2518,18 +790,12 @@ export declare const components: { model: "user"; update: { createdAt?: number; - displayUsername?: null | string; email?: string; emailVerified?: boolean; image?: null | string; - isAnonymous?: null | boolean; name?: string; - phoneNumber?: null | string; - phoneNumberVerified?: null | boolean; - twoFactorEnabled?: null | boolean; updatedAt?: number; userId?: null | string; - username?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; @@ -2540,12 +806,6 @@ export declare const components: { | "image" | "createdAt" | "updatedAt" - | "twoFactorEnabled" - | "isAnonymous" - | "username" - | "displayUsername" - | "phoneNumber" - | "phoneNumberVerified" | "userId" | "id"; operator?: @@ -2700,444 +960,6 @@ export declare const components: { | null; }>; } - | { - model: "twoFactor"; - update: { - backupCodes?: string; - secret?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "secret" | "backupCodes" | "userId" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "passkey"; - update: { - aaguid?: null | string; - backedUp?: boolean; - counter?: number; - createdAt?: null | number; - credentialID?: string; - deviceType?: string; - name?: null | string; - publicKey?: string; - transports?: null | string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "publicKey" - | "userId" - | "credentialID" - | "counter" - | "deviceType" - | "backedUp" - | "transports" - | "createdAt" - | "aaguid" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthApplication"; - update: { - clientId?: null | string; - clientSecret?: null | string; - createdAt?: null | number; - disabled?: null | boolean; - icon?: null | string; - metadata?: null | string; - name?: null | string; - redirectURLs?: null | string; - type?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "icon" - | "metadata" - | "clientId" - | "clientSecret" - | "redirectURLs" - | "type" - | "disabled" - | "userId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthAccessToken"; - update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; - createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "oauthConsent"; - update: { - clientId?: null | string; - consentGiven?: null | boolean; - createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "clientId" - | "userId" - | "scopes" - | "createdAt" - | "updatedAt" - | "consentGiven" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "team"; - update: { - createdAt?: number; - name?: string; - organizationId?: string; - updatedAt?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "organizationId" - | "createdAt" - | "updatedAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "teamMember"; - update: { - createdAt?: null | number; - teamId?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "teamId" | "userId" | "createdAt" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "organization"; - update: { - createdAt?: number; - logo?: null | string; - metadata?: null | string; - name?: string; - slug?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "name" - | "slug" - | "logo" - | "createdAt" - | "metadata" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "member"; - update: { - createdAt?: number; - organizationId?: string; - role?: string; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "userId" - | "role" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "invitation"; - update: { - email?: string; - expiresAt?: number; - inviterId?: string; - organizationId?: string; - role?: null | string; - status?: string; - teamId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "organizationId" - | "email" - | "role" - | "teamId" - | "status" - | "expiresAt" - | "inviterId" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ssoProvider"; - update: { - domain?: string; - issuer?: string; - oidcConfig?: null | string; - organizationId?: null | string; - providerId?: string; - samlConfig?: null | string; - userId?: null | string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "issuer" - | "oidcConfig" - | "samlConfig" - | "userId" - | "providerId" - | "organizationId" - | "domain" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } | { model: "jwks"; update: { @@ -3167,165 +989,11 @@ export declare const components: { | Array | null; }>; - } - | { - model: "subscription"; - update: { - cancelAtPeriodEnd?: null | boolean; - periodEnd?: null | number; - periodStart?: null | number; - plan?: string; - referenceId?: string; - seats?: null | number; - status?: null | string; - stripeCustomerId?: null | string; - stripeSubscriptionId?: null | string; - trialEnd?: null | number; - trialStart?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "plan" - | "referenceId" - | "stripeCustomerId" - | "stripeSubscriptionId" - | "status" - | "periodStart" - | "periodEnd" - | "trialStart" - | "trialEnd" - | "cancelAtPeriodEnd" - | "seats" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "walletAddress"; - update: { - address?: string; - chainId?: number; - createdAt?: number; - isPrimary?: null | boolean; - userId?: string; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: - | "userId" - | "address" - | "chainId" - | "isPrimary" - | "createdAt" - | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "rateLimit"; - update: { - count?: null | number; - key?: null | string; - lastRequest?: null | number; - }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; - } - | { - model: "ratelimit"; - update: { count?: number; key?: string; lastRequest?: number }; - where?: Array<{ - connector?: "AND" | "OR"; - field: "key" | "count" | "lastRequest" | "id"; - operator?: - | "lt" - | "lte" - | "gt" - | "gte" - | "eq" - | "in" - | "ne" - | "contains" - | "starts_with" - | "ends_with"; - value: - | string - | number - | boolean - | Array - | Array - | null; - }>; }; onUpdateHandle?: string; }, any >; }; - adapterTest: { - count: FunctionReference<"query", "internal", any, any>; - create: FunctionReference<"mutation", "internal", any, any>; - delete: FunctionReference<"mutation", "internal", any, any>; - deleteMany: FunctionReference<"mutation", "internal", any, any>; - findMany: FunctionReference<"query", "internal", any, any>; - findOne: FunctionReference<"query", "internal", any, any>; - update: FunctionReference<"mutation", "internal", any, any>; - updateMany: FunctionReference<"mutation", "internal", any, any>; - }; }; }; diff --git a/packages/convex/auth.config.ts b/packages/convex/auth.config.ts index 4cd141c..2c6bcd4 100644 --- a/packages/convex/auth.config.ts +++ b/packages/convex/auth.config.ts @@ -1,4 +1,4 @@ -const authConfig = { +export default { providers: [ { domain: process.env.CONVEX_SITE_URL, @@ -6,5 +6,3 @@ const authConfig = { }, ], } - -export default authConfig diff --git a/packages/convex/auth.ts b/packages/convex/auth.ts index a8d1fe6..23fd633 100644 --- a/packages/convex/auth.ts +++ b/packages/convex/auth.ts @@ -3,26 +3,33 @@ import { convex, crossDomain } from "@convex-dev/better-auth/plugins" import { betterAuth } from "better-auth" import { components } from "./_generated/api" import type { DataModel } from "./_generated/dataModel" +import authSchema from "./betterauth/schema" const siteUrl = process.env.SITE_URL! // The component client has methods needed for integrating Convex with Better Auth, // as well as helper methods for general use. -export const authComponent = createClient(components.betterAuth, { - triggers: { - user: { - onCreate: async (ctx, user) => { - const now = Date.now() - await ctx.db.insert("directories", { - name: "", - userId: user._id, - createdAt: now, - updatedAt: now, - }) +export const authComponent = createClient( + components.betterAuth, + { + local: { + schema: authSchema, + }, + triggers: { + user: { + onCreate: async (ctx, user) => { + const now = Date.now() + await ctx.db.insert("directories", { + name: "", + userId: user._id, + createdAt: now, + updatedAt: now, + }) + }, }, }, }, -}) +) export const createAuth = ( ctx: GenericCtx, diff --git a/packages/convex/betterauth/_generated/api.d.ts b/packages/convex/betterauth/_generated/api.d.ts new file mode 100644 index 0000000..296768f --- /dev/null +++ b/packages/convex/betterauth/_generated/api.d.ts @@ -0,0 +1,971 @@ +/* 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"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{ + adapter: typeof adapter; + auth: typeof auth; +}>; +export type Mounts = { + adapter: { + create: FunctionReference< + "mutation", + "public", + { + 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; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + }; + onCreateHandle?: string; + select?: Array; + }, + any + >; + deleteMany: FunctionReference< + "mutation", + "public", + { + input: + | { + model: "user"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "name" + | "email" + | "emailVerified" + | "image" + | "createdAt" + | "updatedAt" + | "userId" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "session"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "expiresAt" + | "token" + | "createdAt" + | "updatedAt" + | "ipAddress" + | "userAgent" + | "userId" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "verification"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "identifier" + | "value" + | "expiresAt" + | "createdAt" + | "updatedAt" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: "publicKey" | "privateKey" | "createdAt" | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }; + onDeleteHandle?: string; + paginationOpts: { + cursor: string | null; + endCursor?: string | null; + id?: number; + maximumBytesRead?: number; + maximumRowsRead?: number; + numItems: number; + }; + }, + any + >; + deleteOne: FunctionReference< + "mutation", + "public", + { + input: + | { + model: "user"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "name" + | "email" + | "emailVerified" + | "image" + | "createdAt" + | "updatedAt" + | "userId" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "session"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "expiresAt" + | "token" + | "createdAt" + | "updatedAt" + | "ipAddress" + | "userAgent" + | "userId" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "verification"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "identifier" + | "value" + | "expiresAt" + | "createdAt" + | "updatedAt" + | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: "publicKey" | "privateKey" | "createdAt" | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }; + onDeleteHandle?: string; + }, + any + >; + findMany: FunctionReference< + "query", + "public", + { + 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; + }; + sortBy?: { direction: "asc" | "desc"; field: string }; + where?: Array<{ + connector?: "AND" | "OR"; + field: string; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }, + any + >; + findOne: FunctionReference< + "query", + "public", + { + model: "user" | "session" | "account" | "verification" | "jwks"; + select?: Array; + where?: Array<{ + connector?: "AND" | "OR"; + field: string; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }, + any + >; + updateMany: FunctionReference< + "mutation", + "public", + { + 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; + update: { + createdAt?: number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: "publicKey" | "privateKey" | "createdAt" | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }; + onUpdateHandle?: string; + paginationOpts: { + cursor: string | null; + endCursor?: string | null; + id?: number; + maximumBytesRead?: number; + maximumRowsRead?: number; + numItems: number; + }; + }, + any + >; + updateOne: FunctionReference< + "mutation", + "public", + { + 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | 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" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; + update: { + createdAt?: number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: "publicKey" | "privateKey" | "createdAt" | "id"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + }; + onUpdateHandle?: string; + }, + any + >; + }; +}; +// For now fullApiWithMounts is only fullApi which provides +// jump-to-definition in component client code. +// Use Mounts for the same type without the inference. +declare const fullApiWithMounts: typeof fullApi; + +export declare const api: FilterApi< + typeof fullApiWithMounts, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApiWithMounts, + FunctionReference +>; + +export declare const components: {}; diff --git a/packages/convex/betterauth/_generated/api.js b/packages/convex/betterauth/_generated/api.js new file mode 100644 index 0000000..44bf985 --- /dev/null +++ b/packages/convex/betterauth/_generated/api.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi, componentsGeneric } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; +export const components = componentsGeneric(); diff --git a/packages/convex/betterauth/_generated/dataModel.d.ts b/packages/convex/betterauth/_generated/dataModel.d.ts new file mode 100644 index 0000000..8541f31 --- /dev/null +++ b/packages/convex/betterauth/_generated/dataModel.d.ts @@ -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; + +/** + * The type of a document stored in Convex. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Doc = 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(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 = + GenericId; + +/** + * 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; diff --git a/packages/convex/betterauth/_generated/server.d.ts b/packages/convex/betterauth/_generated/server.d.ts new file mode 100644 index 0000000..b5c6828 --- /dev/null +++ b/packages/convex/betterauth/_generated/server.d.ts @@ -0,0 +1,149 @@ +/* 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 { + ActionBuilder, + AnyComponents, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, + FunctionReference, +} from "convex/server"; +import type { DataModel } from "./dataModel.js"; + +type GenericCtx = + | GenericActionCtx + | GenericMutationCtx + | GenericQueryCtx; + +/** + * 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 declare const query: QueryBuilder; + +/** + * 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 declare const internalQuery: QueryBuilder; + +/** + * 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 declare const mutation: MutationBuilder; + +/** + * 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 declare const internalMutation: MutationBuilder; + +/** + * 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 declare const action: ActionBuilder; + +/** + * 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 declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This 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 action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * 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. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * 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. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * 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; + +/** + * 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; + +/** + * 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; diff --git a/packages/convex/betterauth/_generated/server.js b/packages/convex/betterauth/_generated/server.js new file mode 100644 index 0000000..4a21df4 --- /dev/null +++ b/packages/convex/betterauth/_generated/server.js @@ -0,0 +1,90 @@ +/* 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 { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, + componentsGeneric, +} from "convex/server"; + +/** + * 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 = 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 = 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 = 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 = 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 = 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 = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/packages/convex/betterauth/adapter.ts b/packages/convex/betterauth/adapter.ts new file mode 100644 index 0000000..0cade88 --- /dev/null +++ b/packages/convex/betterauth/adapter.ts @@ -0,0 +1,13 @@ +import { createApi } from "@convex-dev/better-auth"; +import schema from "./schema"; +import { createAuth } from "../auth"; + +export const { + create, + findOne, + findMany, + updateOne, + updateMany, + deleteOne, + deleteMany, +} = createApi(schema, createAuth); \ No newline at end of file diff --git a/packages/convex/betterauth/auth.ts b/packages/convex/betterauth/auth.ts new file mode 100644 index 0000000..8a610a7 --- /dev/null +++ b/packages/convex/betterauth/auth.ts @@ -0,0 +1,5 @@ +import { createAuth } from '../auth' +import { getStaticAuth } from '@convex-dev/better-auth' + +// Export a static instance for Better Auth schema generation +export const auth = getStaticAuth(createAuth) \ No newline at end of file diff --git a/packages/convex/betterauth/convex.config.ts b/packages/convex/betterauth/convex.config.ts new file mode 100644 index 0000000..0b28bff --- /dev/null +++ b/packages/convex/betterauth/convex.config.ts @@ -0,0 +1,5 @@ +import { defineComponent } from "convex/server"; + +const component = defineComponent("betterAuth"); + +export default component; \ No newline at end of file diff --git a/packages/convex/betterauth/schema.ts b/packages/convex/betterauth/schema.ts new file mode 100644 index 0000000..167d19f --- /dev/null +++ b/packages/convex/betterauth/schema.ts @@ -0,0 +1,70 @@ +// This file is auto-generated. Do not edit this file manually. +// To regenerate the schema, run: +// `npx @better-auth/cli generate --output undefined -y` + +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(), + }), +}; + +const schema = defineSchema(tables); + +export default schema; diff --git a/packages/convex/convex.config.ts b/packages/convex/convex.config.ts index 6436283..28ca1f6 100644 --- a/packages/convex/convex.config.ts +++ b/packages/convex/convex.config.ts @@ -1,5 +1,5 @@ -import betterAuth from "@convex-dev/better-auth/convex.config" import { defineApp } from "convex/server" +import betterAuth from "./betterauth/convex.config" const app = defineApp() app.use(betterAuth) diff --git a/packages/convex/convex/_generated/api.d.ts b/packages/convex/convex/_generated/api.d.ts new file mode 100644 index 0000000..7d71a01 --- /dev/null +++ b/packages/convex/convex/_generated/api.d.ts @@ -0,0 +1,33 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + ApiFromModules, + FilterApi, + FunctionReference, +} from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{}>; +export declare const api: FilterApi< + typeof fullApi, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApi, + FunctionReference +>; diff --git a/packages/convex/convex/_generated/api.js b/packages/convex/convex/_generated/api.js new file mode 100644 index 0000000..3f9c482 --- /dev/null +++ b/packages/convex/convex/_generated/api.js @@ -0,0 +1,22 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; diff --git a/packages/convex/convex/_generated/dataModel.d.ts b/packages/convex/convex/_generated/dataModel.d.ts new file mode 100644 index 0000000..fb12533 --- /dev/null +++ b/packages/convex/convex/_generated/dataModel.d.ts @@ -0,0 +1,58 @@ +/* eslint-disable */ +/** + * Generated data model types. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { AnyDataModel } from "convex/server"; +import type { GenericId } from "convex/values"; + +/** + * No `schema.ts` file found! + * + * This generated code has permissive types like `Doc = any` because + * Convex doesn't know your schema. If you'd like more type safety, see + * https://docs.convex.dev/using/schemas for instructions on how to add a + * schema file. + * + * After you change a schema, rerun codegen with `npx convex dev`. + */ + +/** + * The names of all of your Convex tables. + */ +export type TableNames = string; + +/** + * The type of a document stored in Convex. + */ +export type Doc = any; + +/** + * 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(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. + */ +export type Id = + GenericId; + +/** + * 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 = AnyDataModel; diff --git a/packages/convex/convex/_generated/server.d.ts b/packages/convex/convex/_generated/server.d.ts new file mode 100644 index 0000000..7f337a4 --- /dev/null +++ b/packages/convex/convex/_generated/server.d.ts @@ -0,0 +1,142 @@ +/* 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 { + ActionBuilder, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, +} 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 declare const query: QueryBuilder; + +/** + * 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 declare const internalQuery: QueryBuilder; + +/** + * 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 declare const mutation: MutationBuilder; + +/** + * 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 declare const internalMutation: MutationBuilder; + +/** + * 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 declare const action: ActionBuilder; + +/** + * 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 declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This 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 action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * 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. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * 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. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * 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; + +/** + * 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; + +/** + * 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; diff --git a/packages/convex/convex/_generated/server.js b/packages/convex/convex/_generated/server.js new file mode 100644 index 0000000..566d485 --- /dev/null +++ b/packages/convex/convex/_generated/server.js @@ -0,0 +1,89 @@ +/* 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 { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, +} from "convex/server"; + +/** + * 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 = 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 = 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 = 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 = 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 = 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 = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index c9a1ba1..7419998 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -7,6 +7,12 @@ import { createContext, useContext } from "react" export type AuthErrorCode = keyof typeof authClient.$ERROR_CODES +export class BetterAuthError extends Error { + constructor(public readonly errorCode: AuthErrorCode) { + super(`better-auth error: ${errorCode}`) + } +} + export const authClient = createAuthClient({ baseURL: process.env.BUN_PUBLIC_CONVEX_SITE_URL, plugins: [convexClient(), crossDomainClient()], diff --git a/packages/web/src/routes/__root.tsx b/packages/web/src/routes/__root.tsx index 3889540..ced3de9 100644 --- a/packages/web/src/routes/__root.tsx +++ b/packages/web/src/routes/__root.tsx @@ -13,7 +13,9 @@ export const Route = createRootRoute({ component: RootLayout, }) -const convexClient = new ConvexReactClient(process.env.BUN_PUBLIC_CONVEX_URL!) +const convexClient = new ConvexReactClient(process.env.BUN_PUBLIC_CONVEX_URL!, { + verbose: true, +}) const queryClient = new QueryClient({ defaultOptions: { mutations: { diff --git a/packages/web/src/routes/_authenticated.tsx b/packages/web/src/routes/_authenticated.tsx index 724c94b..05af757 100644 --- a/packages/web/src/routes/_authenticated.tsx +++ b/packages/web/src/routes/_authenticated.tsx @@ -20,7 +20,7 @@ export const Route = createFileRoute("/_authenticated")({ function AuthenticatedLayout() { const { search } = useLocation() - const { isLoading } = useConvexAuth() + const { isLoading, isAuthenticated } = useConvexAuth() const { data: session, isPending: sessionLoading } = authClient.useSession() const [hasProcessedAuth, setHasProcessedAuth] = useState(false) @@ -33,7 +33,7 @@ function AuthenticatedLayout() { // Delay to ensure auth state is fully synchronized const timer = setTimeout(() => { setHasProcessedAuth(true) - }, 500) + }, 0) return () => clearTimeout(timer) } }, [sessionLoading, isLoading]) @@ -58,7 +58,7 @@ function AuthenticatedLayout() { - + {/* */}
diff --git a/packages/web/src/routes/login.tsx b/packages/web/src/routes/login.tsx index 2340456..93491d0 100644 --- a/packages/web/src/routes/login.tsx +++ b/packages/web/src/routes/login.tsx @@ -1,5 +1,24 @@ +import { useMutation } from "@tanstack/react-query" import { createFileRoute } from "@tanstack/react-router" -import { Button } from "../components/ui/button" +import { GalleryVerticalEnd } from "lucide-react" +import { Button } from "@/components/ui/button" +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { + Field, + FieldDescription, + FieldGroup, + FieldLabel, + FieldSeparator, +} from "@/components/ui/field" +import { Input } from "@/components/ui/input" +import { cn } from "@/lib/utils" +import { type AuthErrorCode, authClient, BetterAuthError } from "../auth" export const Route = createFileRoute("/login")({ component: RouteComponent, @@ -7,8 +26,159 @@ export const Route = createFileRoute("/login")({ function RouteComponent() { return ( -
- + ) } + +function LoginFormCard({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ + + Welcome back + + Login with your Apple or Google account + + + + + + + + By clicking continue, you agree to our{" "} + Terms of Service and{" "} + Privacy Policy. + +
+ ) +} + +function LoginForm() { + const { + mutate: signIn, + isPending, + error: signInError, + } = useMutation({ + mutationFn: async ({ + email, + password, + }: { + email: string + password: string + }) => { + const { data: signInData, error } = await authClient.signIn.email({ + email, + password, + callbackURL: "/home", + rememberMe: true, + }) + if (error) { + throw new BetterAuthError(error.code as AuthErrorCode) + } + return signInData + }, + }) + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault() + const formData = new FormData(event.currentTarget) + signIn({ + email: formData.get("email") as string, + password: formData.get("password") as string, + }) + } + + return ( +
+ + + + + + + Or continue with + + + Email + + + + + + + + + + Don't have an account? Sign up + + + +
+ ) +} diff --git a/packages/web/src/routes/sign-up.tsx b/packages/web/src/routes/sign-up.tsx index 8757382..5f50fde 100644 --- a/packages/web/src/routes/sign-up.tsx +++ b/packages/web/src/routes/sign-up.tsx @@ -19,7 +19,7 @@ import { FieldLabel, } from "@/components/ui/field" import { Input } from "@/components/ui/input" -import { type AuthErrorCode, authClient } from "../auth" +import { type AuthErrorCode, authClient, BetterAuthError } from "../auth" export const Route = createFileRoute("/sign-up")({ component: SignupPage, @@ -38,12 +38,6 @@ class PasswordMismatchError extends Error { } } -class BetterAuthError extends Error { - constructor(public readonly errorCode: AuthErrorCode) { - super(`better-auth error: ${errorCode}`) - } -} - function SignupPage() { return (