diff --git a/.env.example b/.env.example
index 333941b..f76ede7 100644
--- a/.env.example
+++ b/.env.example
@@ -1,2 +1,4 @@
NODE_ENV="development"
DATABASE_URL=""
+CLERK_SECRET_KEY=""
+VITE_CLERK_PUBLISHABLE_KEY=""
diff --git a/app/root.tsx b/app/root.tsx
index 9fc6636..87a29d0 100644
--- a/app/root.tsx
+++ b/app/root.tsx
@@ -9,6 +9,18 @@ import {
import type { Route } from "./+types/root";
import "./app.css";
+import { rootAuthLoader } from "@clerk/react-router/server";
+import {
+ ClerkProvider,
+ SignedOut,
+ SignInButton,
+ UserButton,
+ SignedIn,
+} from "@clerk/react-router";
+
+export async function loader(args: Route.LoaderArgs) {
+ return rootAuthLoader(args);
+}
export const links: Route.LinksFunction = () => [
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
@@ -41,8 +53,22 @@ export function Layout({ children }: { children: React.ReactNode }) {
);
}
-export default function App() {
- return ;
+export default function App({ loaderData }: Route.ComponentProps) {
+ return (
+
+
+
+
+
+
+ );
}
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
diff --git a/package-lock.json b/package-lock.json
index 369df01..eb155b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,6 +6,7 @@
"": {
"name": "brackt.com",
"dependencies": {
+ "@clerk/react-router": "^2.1.0",
"@react-router/express": "^7.7.1",
"@react-router/node": "^7.7.1",
"compression": "^1.8.0",
@@ -501,6 +502,113 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@clerk/backend": {
+ "version": "2.17.2",
+ "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-2.17.2.tgz",
+ "integrity": "sha512-zgKySfoOXySYOMEDc+S2vXLchCldwPVb85tyvP1NnmxvgyAm10yCA+xd4No4dNWm+lwkwHuNWX3rM9ro8khSmw==",
+ "license": "MIT",
+ "dependencies": {
+ "@clerk/shared": "^3.27.3",
+ "@clerk/types": "^4.92.0",
+ "cookie": "1.0.2",
+ "standardwebhooks": "^1.0.0",
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=18.17.0"
+ }
+ },
+ "node_modules/@clerk/backend/node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@clerk/clerk-react": {
+ "version": "5.51.0",
+ "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.51.0.tgz",
+ "integrity": "sha512-jBreKiUS4DKm+JUIt59B1699aRr3wQmQ1O+DlWCEY3iEz+F6ETir1SJcRNG5mHVoA9EGn+m93USJSUWZBRG8yQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@clerk/shared": "^3.27.3",
+ "@clerk/types": "^4.92.0",
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=18.17.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
+ }
+ },
+ "node_modules/@clerk/react-router": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@clerk/react-router/-/react-router-2.1.0.tgz",
+ "integrity": "sha512-qAfMxiiPmSs7Vv5oj1qXYedyCrGnL4c/susr2P74BW07Fyz13wT1/ZEJ5Y4g+u1GGSPxvbQtv8OWsNIsulclKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@clerk/backend": "^2.17.2",
+ "@clerk/clerk-react": "^5.51.0",
+ "@clerk/shared": "^3.27.3",
+ "@clerk/types": "^4.92.0",
+ "cookie": "0.7.2",
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
+ "react-router": "^7.9.0"
+ }
+ },
+ "node_modules/@clerk/shared": {
+ "version": "3.27.3",
+ "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-3.27.3.tgz",
+ "integrity": "sha512-OJqWwlQGi6XMVWJVtY1YmOESAkEAflDrynFSjwQQ/sC8c4hmUukIq07XTOlcv6j4u1i4akhtNwy40B1qiRrLdg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@clerk/types": "^4.92.0",
+ "dequal": "2.0.3",
+ "glob-to-regexp": "0.4.1",
+ "js-cookie": "3.0.5",
+ "std-env": "^3.9.0",
+ "swr": "2.3.4"
+ },
+ "engines": {
+ "node": ">=18.17.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@clerk/types": {
+ "version": "4.92.0",
+ "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.92.0.tgz",
+ "integrity": "sha512-+bUiHjqVXEHJIOOhshIy3uYDF/c4/yNc2BPfgPTXxxsbz/2wG0XUx0PL+mxUPiruPZOD+D63AtmORuFW3yBa2w==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "3.1.3"
+ },
+ "engines": {
+ "node": ">=18.17.0"
+ }
+ },
"node_modules/@drizzle-team/brocli": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz",
@@ -1968,6 +2076,12 @@
"win32"
]
},
+ "node_modules/@stablelib/base64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
+ "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
+ "license": "MIT"
+ },
"node_modules/@tailwindcss/node": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
@@ -2837,7 +2951,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "devOptional": true,
"license": "MIT"
},
"node_modules/debug": {
@@ -2881,6 +2994,15 @@
"node": ">= 0.8"
}
},
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -3311,6 +3433,12 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/fast-sha256": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
+ "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==",
+ "license": "Unlicense"
+ },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -3486,6 +3614,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
@@ -3685,6 +3819,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/js-cookie": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
+ "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5035,6 +5178,16 @@
"dev": true,
"license": "CC0-1.0"
},
+ "node_modules/standardwebhooks": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz",
+ "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==",
+ "license": "MIT",
+ "dependencies": {
+ "@stablelib/base64": "^1.0.0",
+ "fast-sha256": "^1.3.0"
+ }
+ },
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
@@ -5044,6 +5197,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/std-env": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
+ "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
+ "license": "MIT"
+ },
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@@ -5148,6 +5307,19 @@
"node": ">=8"
}
},
+ "node_modules/swr": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.4.tgz",
+ "integrity": "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg==",
+ "license": "MIT",
+ "dependencies": {
+ "dequal": "^2.0.3",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
@@ -5243,6 +5415,12 @@
}
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/tsx": {
"version": "4.20.6",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
@@ -5771,6 +5949,15 @@
"browserslist": ">= 4.21.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/valibot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.1.0.tgz",
diff --git a/package.json b/package.json
index fb68033..4808402 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"typecheck": "react-router typegen && tsc -b"
},
"dependencies": {
+ "@clerk/react-router": "^2.1.0",
"@react-router/express": "^7.7.1",
"@react-router/node": "^7.7.1",
"compression": "^1.8.0",
@@ -42,4 +43,4 @@
"vite": "^6.3.3",
"vite-tsconfig-paths": "^5.1.4"
}
-}
\ No newline at end of file
+}