diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d447141..6c2f30e 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -17,23 +17,17 @@ module.exports = { project: true }, overrides: [ - /** - * Disable type checking for JavaScript files - */ - // { - // files: ["*.js"], - // extends: ["plugin:@typescript-eslint/disable-type-checked"] - // }, /** * Config files (ex: jest.config.js, prettier.config.js, tailwind.config.js) */ { - files: ["*.config.js"], + files: ["*.config.{js,ts}"], env: { node: true }, rules: { - "@typescript-eslint/no-var-requires": "off" + "@typescript-eslint/no-var-requires": "off", + "import/no-default-export": "off" } }, /** diff --git a/auth.config.ts b/auth.config.ts index 4f55e0f..5414817 100644 --- a/auth.config.ts +++ b/auth.config.ts @@ -6,12 +6,9 @@ import { HttpEmailProvider } from "@/lib/auth/http-email-provider" import { adapter } from "./lib/db/adapter" -/** - * https://auth-docs-git-feat-nextjs-auth-authjs.vercel.app/guides/upgrade-to-v5#edge-compatibility - */ export default { /** - * https://authjs.dev/reference/adapter/drizzle + * @see {@link https://authjs.dev/reference/adapter/drizzle} */ adapter, diff --git a/auth.ts b/auth.ts index 0a51eb0..1dd9e65 100644 --- a/auth.ts +++ b/auth.ts @@ -6,6 +6,7 @@ declare module "next-auth" { /** * Add additional attributes to the session object. */ + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- This is a module augmentation interface Session { user?: { /** The user's id. */ @@ -13,6 +14,7 @@ declare module "next-auth" { } & DefaultSession["user"] } } + /** * * All NextAuth config should be defined in `./auth.config.ts` to allow for us diff --git a/bin/setup b/bin/setup index 75b9ad9..2e29186 100755 --- a/bin/setup +++ b/bin/setup @@ -1,5 +1,20 @@ #!/usr/bin/env sh +# This function adds a secret to the .env.local file, unless the key is already +# defined. This allows us to add new default values even if a .env.local file +# alrady exists +define_secret() { + local secret_name=$1 + local secret_value=$2 + + if ! grep -q "^${secret_name}=" .env.local; then + echo " > Setting '${secret_name}' ..." + echo "${secret_name}=\"${secret_value}\"" >> .env.local + else + echo " > '${secret_name}' already defined, skipping ..." + fi +} + # # Install dependencies # @@ -9,14 +24,12 @@ bun install --frozen-lockfile # # Create a .env.local file and popupate it with auto-generated secrets # -if ! [ -f .env.local ]; then - echo "\n✨ Creating a .env.local file for local environment variables..." - touch .env.local +echo "\n✨ Creating a .env.local file for local environment variables..." +touch .env.local - echo "\n✨ Generating a secure value for local AUTH_SECRET ..." - echo "AUTH_SECRET=\"$(openssl rand -base64 32)\"" >> .env.local - echo "AUTH_URL=\"http://localhost:3000\"" >> .env.local -fi +echo "\n✨ Generating a secure value for local AUTH_SECRET ..." +define_secret "AUTH_SECRET" "$(openssl rand -base64 32)" +define_secret "AUTH_URL" "http://localhost:3000/api/auth" # # Migrate the database diff --git a/bun.lockb b/bun.lockb index 4a8771c..65cb31a 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/lib/auth/http-email-provider.ts b/lib/auth/http-email-provider.ts index d816cf9..bff8212 100644 --- a/lib/auth/http-email-provider.ts +++ b/lib/auth/http-email-provider.ts @@ -1,16 +1,21 @@ import { type Provider } from "next-auth/providers" +import { env } from "@/env" + import { sendVerificationRequest } from "./send-verification-request" /** * This defines an HTTP email provider, which is used for sending verification * requests to the user's email. * - * https://authjs.dev/guides/providers/email-http#introduction + * @see {@link https://authjs.dev/guides/providers/email-http#introduction} */ export const HttpEmailProvider: Provider = { id: "http-email", - // @ts-expect-error Provider["type"] doesn't allow email, but it should type: "email", + name: "HTTP Email", + from: env.EMAIL_FROM, + maxAge: 24 * 60 * 60, + options: {}, sendVerificationRequest } diff --git a/lib/auth/send-verification-request.tsx b/lib/auth/send-verification-request.tsx index 9ee6900..3ec41c5 100644 --- a/lib/auth/send-verification-request.tsx +++ b/lib/auth/send-verification-request.tsx @@ -1,5 +1,5 @@ import { eq } from "drizzle-orm" -import { type SendVerificationRequestParams } from "next-auth/providers" +import { type EmailConfig } from "next-auth/providers" import { usersTable } from "@/drizzle/schema" import SignInEmail from "@/emails/signin-email" @@ -7,6 +7,10 @@ import { env } from "@/env" import { db } from "@/lib/db" import { emailClient } from "@/lib/email" +type SendVerificationRequestParams = Parameters< + EmailConfig["sendVerificationRequest"] +>[0] + export async function sendVerificationRequest({ identifier: email, url diff --git a/lib/db/client.ts b/lib/db/client.ts index 5465b14..87370b2 100644 --- a/lib/db/client.ts +++ b/lib/db/client.ts @@ -1,13 +1,20 @@ -import { neon, neonConfig } from "@neondatabase/serverless" +import { + type NeonQueryFunction, + neon, + neonConfig +} from "@neondatabase/serverless" import { drizzle } from "drizzle-orm/neon-http" import { env } from "@/env" /** * Opt-in to experimental connection caching - * https://neon.tech/docs/serverless/serverless-driver#use-experimental-caching + * @see {@link https://neon.tech/docs/serverless/serverless-driver#use-experimental-caching} */ neonConfig.fetchConnectionCache = true -export const client = neon(env.DATABASE_URL_POOLED ?? env.DATABASE_URL) +export const client = neon(env.DATABASE_URL) satisfies NeonQueryFunction< + boolean, + boolean +> export const db = drizzle(client) diff --git a/package.json b/package.json index 1027588..3a7bffd 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,10 @@ "type-check": "tsc --noEmit --pretty" }, "dependencies": { - "@auth/core": "^0.22.0", - "@auth/drizzle-adapter": "0.3.16", + "@auth/core": "^0.27.0", + "@auth/drizzle-adapter": "0.7.0", "@hookform/resolvers": "^3.3.4", - "@neondatabase/serverless": "^0.7.2", + "@neondatabase/serverless": "^0.8.1", "@next/mdx": "^14.1.0", "@paralleldrive/cuid2": "^2.2.2", "@radix-ui/react-alert-dialog": "^1.0.5", @@ -36,53 +36,54 @@ "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", - "@react-email/components": "0.0.14", + "@react-email/components": "0.0.15", "@react-email/render": "^0.0.12", - "@t3-oss/env-nextjs": "^0.7.3", + "@t3-oss/env-nextjs": "^0.9.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", - "drizzle-orm": "^0.29.3", - "geist": "^1.2.1", - "lucide-react": "^0.314.0", + "drizzle-orm": "^0.29.4", + "geist": "^1.2.2", + "lucide-react": "^0.338.0", "next": "^14.1.0", - "next-auth": "5.0.0-beta.3", + "next-auth": "5.0.0-beta.13", "next-themes": "^0.2.1", "nextjs-google-analytics": "^2.3.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-hook-form": "^7.49.3", - "resend": "^3.0.0", - "sonner": "^1.3.1", - "tailwind-merge": "^2.2.0", - "typed-route-handler": "^0.0.5", + "react-hook-form": "^7.50.1", + "resend": "^3.2.0", + "sonner": "^1.4.1", + "tailwind-merge": "^2.2.1", + "typed-route-handler": "^0.1.1", "zod": "^3.22.4" }, "devDependencies": { "@tailwindcss/typography": "^0.5.10", - "@testing-library/jest-dom": "^6.2.0", - "@testing-library/react": "^14.1.2", - "@types/jest": "^29.5.11", - "@types/mdx": "^2.0.10", - "@types/node": "^20.11.5", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@vercel/style-guide": "^5.1.0", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "^14.2.1", + "@types/jest": "^29.5.12", + "@types/mdx": "^2.0.11", + "@types/node": "^20.11.20", + "@types/react": "^18.2.58", + "@types/react-dom": "^18.2.19", + "@vercel/style-guide": "^5.2.0", "autoprefixer": "^10.4.17", "concurrently": "^8.2.2", - "drizzle-kit": "^0.20.13", - "eslint": "^8.56.0", + "drizzle-kit": "^0.20.14", + "eslint": "^8.57.0", "eslint-config-next": "^14.1.0", - "eslint-plugin-tailwindcss": "^3.14.0", + "eslint-plugin-tailwindcss": "^3.14.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "next-secure-headers": "^2.2.0", - "oxlint": "^0.2.2", + "oxlint": "^0.2.10", "patch-package": "^8.0.0", "pg": "^8.11.3", - "postcss": "^8.4.33", + "postcss": "^8.4.35", "postgres": "^3.4.3", - "prettier": "^3.2.4", - "react-email": "^2.0.0", + "postinstall-postinstall": "^2.1.0", + "prettier": "^3.2.5", + "react-email": "^2.1.0", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", "typescript": "^5.3.3" diff --git a/patches/@auth+drizzle-adapter+0.3.16.patch b/patches/@auth+drizzle-adapter+0.7.0.patch similarity index 96% rename from patches/@auth+drizzle-adapter+0.3.16.patch rename to patches/@auth+drizzle-adapter+0.7.0.patch index e2b162f..e6024b9 100644 --- a/patches/@auth+drizzle-adapter+0.3.16.patch +++ b/patches/@auth+drizzle-adapter+0.7.0.patch @@ -30,7 +30,7 @@ index 07a8a9e..6a88c04 100644 else if (is(db, BaseSQLiteDatabase)) { return SQLiteDrizzleAdapter(db, table); diff --git a/node_modules/@auth/drizzle-adapter/lib/pg.d.ts b/node_modules/@auth/drizzle-adapter/lib/pg.d.ts -index 1d434a0..0cf755c 100644 +index 600af0e..e08e1f3 100644 --- a/node_modules/@auth/drizzle-adapter/lib/pg.d.ts +++ b/node_modules/@auth/drizzle-adapter/lib/pg.d.ts @@ -295,5 +295,5 @@ export declare function createTables(pgTable: PgTableFn): { @@ -42,10 +42,10 @@ index 1d434a0..0cf755c 100644 //# sourceMappingURL=pg.d.ts.map \ No newline at end of file diff --git a/node_modules/@auth/drizzle-adapter/lib/pg.js b/node_modules/@auth/drizzle-adapter/lib/pg.js -index f3d333f..647fd60 100644 +index 2ae39ca..c0cad4b 100644 --- a/node_modules/@auth/drizzle-adapter/lib/pg.js +++ b/node_modules/@auth/drizzle-adapter/lib/pg.js -@@ -41,13 +41,13 @@ export function createTables(pgTable) { +@@ -42,13 +42,13 @@ export function createTables(pgTable) { })); return { users, accounts, sessions, verificationTokens }; }