diff --git a/app/api/auth/[...nextauth]/options.ts b/app/api/auth/[...nextauth]/options.ts
new file mode 100644
index 0000000..beb5c76
--- /dev/null
+++ b/app/api/auth/[...nextauth]/options.ts
@@ -0,0 +1,24 @@
+import GitHubProvider from "next-auth/providers/github";
+import { NextAuthOptions } from "next-auth";
+
+export const authOptions: NextAuthOptions = {
+ providers: [
+ GitHubProvider({
+ clientId: process.env.GITHUB_CLIENT_ID as string,
+ clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
+ }),
+ ],
+ callbacks: {
+ async jwt({ token, account }) {
+ if (account) {
+ token.accessToken = account.access_token;
+ }
+ return token;
+ },
+ async session({ session, token }) {
+ // Type assertion to let TypeScript know token will have accessToken
+ session.accessToken = (token as { accessToken?: string }).accessToken;
+ return session;
+ },
+ },
+};
diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..9da800b
--- /dev/null
+++ b/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,6 @@
+import NextAuth from "next-auth";
+import { authOptions } from "./options";
+
+const handler = NextAuth(authOptions);
+
+export { handler as GET, handler as POST };
diff --git a/app/layout.tsx b/app/layout.tsx
index fbde2fb..e381c98 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -80,7 +80,6 @@ export default function RootLayout({
children: React.ReactNode;
}) {
const isProduction = process.env.VERCEL_ENV === "production";
-
return (
- {children}
+ {children}
diff --git a/components/auth/auth-menu.tsx b/components/auth/auth-menu.tsx
new file mode 100644
index 0000000..81c8ac2
--- /dev/null
+++ b/components/auth/auth-menu.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import { signIn, signOut, useSession } from "next-auth/react";
+import { Avatar } from "@nextui-org/avatar";
+import { Button } from "@nextui-org/button";
+import {
+ Dropdown,
+ DropdownTrigger,
+ DropdownMenu,
+ DropdownItem,
+} from "@nextui-org/dropdown";
+import { Skeleton } from "@nextui-org/skeleton";
+
+import { GithubIcon } from "@/assets/icons";
+
+const AuthMenu: React.FC = () => {
+ const { data: session, status } = useSession();
+
+ if (status === "loading") {
+ return ;
+ }
+
+ return (
+
+ {session ? (
+
+
+ {/* TODO: Support no image placeholder */}
+
+
+
+ {
+
+ Signed in as
+ {session.user?.name}
+
+ }
+ signOut()}>
+ Log Out
+
+
+
+ ) : (
+
+ )}
+
+ );
+};
+
+export default AuthMenu;
diff --git a/components/cta-banner.tsx b/components/cta-banner.tsx
index f26d32f..9c89de4 100644
--- a/components/cta-banner.tsx
+++ b/components/cta-banner.tsx
@@ -66,7 +66,7 @@ const CtaBanner = ({}: ICtaBannerProps) => {
className="font-semibold border-large hover:underline"
color="danger"
variant="bordered"
- onClick={handleClose}
+ onPress={handleClose}
>
Hide this
diff --git a/components/nav/navbar.tsx b/components/nav/navbar.tsx
index a4d096d..45aea6f 100644
--- a/components/nav/navbar.tsx
+++ b/components/nav/navbar.tsx
@@ -5,12 +5,13 @@ import {
NavbarBrand,
} from "@nextui-org/navbar";
import { Chip } from "@nextui-org/chip";
+import AuthMenu from "@/components/auth/auth-menu";
import { MyImage } from "@/components/ui/image";
+import { getAllProjects } from "@/lib/api/projects";
import { BugReport, CtaButton, FeedbackForms, ProjectDropDown } from "./items";
import Separator from "./separator";
import SocialLinks from "./social-links";
-import { getAllProjects } from "@/lib/api/projects";
export default async function Navbar() {
const projects = await getAllProjects().catch((error) => {
@@ -51,6 +52,9 @@ export default async function Navbar() {
{projects && }
+
);
diff --git a/components/table/row.tsx b/components/table/row.tsx
index 0df0699..4a788f2 100644
--- a/components/table/row.tsx
+++ b/components/table/row.tsx
@@ -347,8 +347,7 @@ interface IApplyButtonProps {
onOpen: () => void;
}
export const ApplyButton = ({ onOpen }: IApplyButtonProps) => {
- const handleClick = (e: React.MouseEvent) => {
- e.stopPropagation();
+ const handleClick = () => {
onOpen();
};
@@ -356,7 +355,7 @@ export const ApplyButton = ({ onOpen }: IApplyButtonProps) => {
diff --git a/middlewares/github.ts b/middlewares/github.ts
new file mode 100644
index 0000000..b369f2b
--- /dev/null
+++ b/middlewares/github.ts
@@ -0,0 +1,4 @@
+export { default } from "next-auth/middleware";
+
+// applies next-auth only to matching routes
+export const config = { matcher: ["/profiles"] };
diff --git a/next.config.js b/next.config.js
index e74a631..8b09827 100644
--- a/next.config.js
+++ b/next.config.js
@@ -16,6 +16,7 @@ const cspHeader = `
const nextConfig = {
images: {
+ remotePatterns: ["avatars.githubusercontent.com"],
formats: ["image/avif", "image/webp"],
remotePatterns: [
{
diff --git a/package.json b/package.json
index b1bc082..568d8b8 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
},
"dependencies": {
"@next/third-parties": "15.1.3",
+ "@nextui-org/avatar": "^2.2.5",
"@nextui-org/button": "2.2.8",
"@nextui-org/card": "^2.2.8",
"@nextui-org/checkbox": "^2.3.7",
@@ -47,6 +48,7 @@
"isomorphic-dompurify": "^2.19.0",
"marked": "^15.0.4",
"next": "15.1.3",
+ "next-auth": "^4.24.10",
"next-themes": "^0.4.4",
"react": "19.0.0",
"react-dom": "19.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index caf5ca3..f587aa9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,6 +14,9 @@ importers:
'@next/third-parties':
specifier: 15.1.3
version: 15.1.3(next@15.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
+ '@nextui-org/avatar':
+ specifier: ^2.2.5
+ version: 2.2.5(@nextui-org/system@2.4.5(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@nextui-org/button':
specifier: 2.2.8
version: 2.2.8(@nextui-org/system@2.4.5(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -119,6 +122,9 @@ importers:
next:
specifier: 15.1.3
version: 15.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ next-auth:
+ specifier: ^4.24.10
+ version: 4.24.11(next@15.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next-themes:
specifier: ^0.4.4
version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -450,6 +456,14 @@ packages:
react: '>=18 || >=19.0.0-rc.0'
react-dom: '>=18 || >=19.0.0-rc.0'
+ '@nextui-org/avatar@2.2.5':
+ resolution: {integrity: sha512-ugpwuH1M+eyWY+6Fb4OgGev1HweRrE61bA3rHxRzR3CcjWoe9g7JoQ04NbNNLUDp+aZuil/RWmgSfGUXEexZVQ==}
+ peerDependencies:
+ '@nextui-org/system': '>=2.4.0'
+ '@nextui-org/theme': '>=2.4.0'
+ react: '>=18 || >=19.0.0-rc.0'
+ react-dom: '>=18 || >=19.0.0-rc.0'
+
'@nextui-org/button@2.2.8':
resolution: {integrity: sha512-Km9ER+jpA3DdYmbh8k30w2DMXZIPtZjs7QVVaPAEW+rJYnGWNsomcltlOLIvHpBYeAbB8hfJCbRJ35r9WeL9Gw==}
peerDependencies:
@@ -789,6 +803,9 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
+ '@panva/hkdf@1.2.1':
+ resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -1410,6 +1427,10 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -2027,6 +2048,9 @@ packages:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
+ jose@4.15.9:
+ resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -2095,6 +2119,10 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+ lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+
marked@15.0.4:
resolution: {integrity: sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw==}
engines: {node: '>= 18'}
@@ -2157,6 +2185,20 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ next-auth@4.24.11:
+ resolution: {integrity: sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==}
+ peerDependencies:
+ '@auth/core': 0.34.2
+ next: ^12.2.5 || ^13 || ^14 || ^15
+ nodemailer: ^6.6.5
+ react: ^17.0.2 || ^18 || ^19
+ react-dom: ^17.0.2 || ^18 || ^19
+ peerDependenciesMeta:
+ '@auth/core':
+ optional: true
+ nodemailer:
+ optional: true
+
next-themes@0.4.4:
resolution: {integrity: sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==}
peerDependencies:
@@ -2198,10 +2240,17 @@ packages:
nwsapi@2.2.16:
resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==}
+ oauth@0.9.15:
+ resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
+ object-hash@2.2.0:
+ resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
+ engines: {node: '>= 6'}
+
object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
@@ -2234,6 +2283,13 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
+ oidc-token-hash@5.0.3:
+ resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==}
+ engines: {node: ^10.13.0 || >=12.0.0}
+
+ openid-client@5.7.1:
+ resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -2339,6 +2395,14 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
+ preact-render-to-string@5.2.6:
+ resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
+ peerDependencies:
+ preact: '>=10'
+
+ preact@10.25.4:
+ resolution: {integrity: sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==}
+
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -2348,6 +2412,9 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ pretty-format@3.8.0:
+ resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
+
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -2741,6 +2808,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ uuid@8.3.2:
+ resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ hasBin: true
+
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
@@ -2813,6 +2884,9 @@ packages:
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+ yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
yaml@2.6.1:
resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==}
engines: {node: '>= 14'}
@@ -3085,6 +3159,19 @@ snapshots:
- '@nextui-org/theme'
- framer-motion
+ '@nextui-org/avatar@2.2.5(@nextui-org/system@2.4.5(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@nextui-org/react-utils': 2.1.2(react@19.0.0)
+ '@nextui-org/shared-utils': 2.1.2
+ '@nextui-org/system': 2.4.5(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@nextui-org/theme': 2.4.4(tailwindcss@3.4.17)
+ '@nextui-org/use-image': 2.1.1(react@19.0.0)
+ '@react-aria/focus': 3.19.0(react@19.0.0)
+ '@react-aria/interactions': 3.22.5(react@19.0.0)
+ '@react-aria/utils': 3.26.0(react@19.0.0)
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+
'@nextui-org/button@2.2.8(@nextui-org/system@2.4.5(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@nextui-org/theme@2.4.4(tailwindcss@3.4.17))(framer-motion@11.15.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@nextui-org/react-utils': 2.1.2(react@19.0.0)
@@ -3677,6 +3764,8 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {}
+ '@panva/hkdf@1.2.1': {}
+
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -4512,6 +4601,8 @@ snapshots:
concat-map@0.0.1: {}
+ cookie@0.7.2: {}
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -5278,6 +5369,8 @@ snapshots:
jiti@1.21.7: {}
+ jose@4.15.9: {}
+
js-tokens@4.0.0: {}
js-yaml@4.1.0:
@@ -5360,6 +5453,10 @@ snapshots:
lru-cache@10.4.3: {}
+ lru-cache@6.0.0:
+ dependencies:
+ yallist: 4.0.0
+
marked@15.0.4: {}
matchmediaquery@0.4.2:
@@ -5409,6 +5506,21 @@ snapshots:
natural-compare@1.4.0: {}
+ next-auth@4.24.11(next@15.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ dependencies:
+ '@babel/runtime': 7.26.0
+ '@panva/hkdf': 1.2.1
+ cookie: 0.7.2
+ jose: 4.15.9
+ next: 15.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ oauth: 0.9.15
+ openid-client: 5.7.1
+ preact: 10.25.4
+ preact-render-to-string: 5.2.6(preact@10.25.4)
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ uuid: 8.3.2
+
next-themes@0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
react: 19.0.0
@@ -5447,8 +5559,12 @@ snapshots:
nwsapi@2.2.16: {}
+ oauth@0.9.15: {}
+
object-assign@4.1.1: {}
+ object-hash@2.2.0: {}
+
object-hash@3.0.0: {}
object-inspect@1.13.3: {}
@@ -5490,6 +5606,15 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.0.0
+ oidc-token-hash@5.0.3: {}
+
+ openid-client@5.7.1:
+ dependencies:
+ jose: 4.15.9
+ lru-cache: 6.0.0
+ object-hash: 2.2.0
+ oidc-token-hash: 5.0.3
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -5587,10 +5712,19 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ preact-render-to-string@5.2.6(preact@10.25.4):
+ dependencies:
+ preact: 10.25.4
+ pretty-format: 3.8.0
+
+ preact@10.25.4: {}
+
prelude-ls@1.2.1: {}
prettier@3.4.2: {}
+ pretty-format@3.8.0: {}
+
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -6070,6 +6204,8 @@ snapshots:
util-deprecate@1.0.2: {}
+ uuid@8.3.2: {}
+
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
@@ -6151,6 +6287,8 @@ snapshots:
xmlchars@2.2.0: {}
+ yallist@4.0.0: {}
+
yaml@2.6.1: {}
yocto-queue@0.1.0: {}
diff --git a/tsconfig.json b/tsconfig.json
index f67aea9..b2d0201 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "typeRoots": ["./types", "./node_modules/@types"],
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts
new file mode 100644
index 0000000..bcc1fb0
--- /dev/null
+++ b/types/next-auth.d.ts
@@ -0,0 +1,17 @@
+import "next-auth";
+
+declare module "next-auth" {
+ interface Session {
+ accessToken?: string; // Add custom properties to the session object
+ user?: {
+ name?: string;
+ email?: string;
+ image?: string;
+ id?: string; // Example: if you include the user's GitHub ID
+ };
+ }
+
+ interface JWT {
+ accessToken?: string;
+ }
+}