Set up clerk auth

This commit is contained in:
2024-06-15 22:22:17 -05:00
parent 42f55b1d60
commit aebc41dc54
15 changed files with 350 additions and 346 deletions

View File

@@ -12,10 +12,5 @@
# Drizzle
POSTGRES_URL="postgresql://postgres:password@localhost:5432/resume-factory"
# Next Auth
# You can generate a new secret on the command line with:
# openssl rand -base64 32
# https://next-auth.js.org/configuration/options#secret
NEXTAUTH_SECRET=""
NEXTAUTH_URL="http://localhost:3000"
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
CLERK_SECRET_KEY=""

402
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@auth/drizzle-adapter": "^0.7.0",
"@clerk/nextjs": "^5.1.5",
"@formkit/auto-animate": "^0.8.2",
"@hookform/resolvers": "^3.4.2",
"@radix-ui/react-accordion": "^1.1.2",
@@ -35,7 +36,6 @@
"lodash.debounce": "^4.0.8",
"lodash.merge": "^4.6.2",
"next": "^14.2.1",
"next-auth": "^4.24.6",
"next-themes": "^0.3.0",
"postgres": "^3.4.3",
"react": "18.2.0",
@@ -132,6 +132,127 @@
"node": ">=6.9.0"
}
},
"node_modules/@clerk/backend": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.2.3.tgz",
"integrity": "sha512-tj812eTTn2ewXMgr4jwFjpqoXZRF2LMw9UBT+Nat0lmXw55sDA5ou2McLZ67e62WNZwbrCUa51MGKSBhrWnZcA==",
"dependencies": {
"@clerk/shared": "2.3.0",
"@clerk/types": "4.6.0",
"cookie": "0.5.0",
"snakecase-keys": "5.4.4",
"tslib": "2.4.1"
},
"engines": {
"node": ">=18.17.0"
}
},
"node_modules/@clerk/backend/node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/@clerk/backend/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@clerk/clerk-react": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.2.4.tgz",
"integrity": "sha512-TaSjf3pdxUKQIDmwi6JkJDVGwHbs7pTeiwEr2/JksMrQnW6zMIutsEhJfW10dY1hOwJeDoSxGCkHw+7Br2rktw==",
"dependencies": {
"@clerk/shared": "2.3.0",
"@clerk/types": "4.6.0",
"tslib": "2.4.1"
},
"engines": {
"node": ">=18.17.0"
},
"peerDependencies": {
"react": ">=18 || >=19.0.0-beta",
"react-dom": ">=18 || >=19.0.0-beta"
}
},
"node_modules/@clerk/clerk-react/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@clerk/nextjs": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-5.1.5.tgz",
"integrity": "sha512-q/4PvWrIt4cO9dwgUyJ/gN/fWbS2GnfKK7j32cn6LBObVqUIiQ+J5Q+lp75q+tzIHyxFJx+MNNTnFif2OrvV6A==",
"dependencies": {
"@clerk/backend": "1.2.3",
"@clerk/clerk-react": "5.2.4",
"@clerk/shared": "2.3.0",
"@clerk/types": "4.6.0",
"crypto-js": "4.2.0",
"path-to-regexp": "6.2.2",
"tslib": "2.4.1"
},
"engines": {
"node": ">=18.17.0"
},
"peerDependencies": {
"next": "^13.5.4 || ^14.0.3 || >=15.0.0-rc",
"react": ">=18 || >=19.0.0-beta",
"react-dom": ">=18 || >=19.0.0-beta"
}
},
"node_modules/@clerk/nextjs/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@clerk/shared": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-2.3.0.tgz",
"integrity": "sha512-V/49MoOrALzpu0BbhYDCcKQYIjrHnhRa7QFho9+4wm94oCJgc9j3N5wxndJwj3Ur/fmIyBnjwMzDAT2nZZj47g==",
"hasInstallScript": true,
"dependencies": {
"@clerk/types": "4.6.0",
"glob-to-regexp": "0.4.1",
"js-cookie": "3.0.5",
"std-env": "^3.7.0",
"swr": "^2.2.0"
},
"engines": {
"node": ">=18.17.0"
},
"peerDependencies": {
"react": ">=18 || >=19.0.0-beta",
"react-dom": ">=18 || >=19.0.0-beta"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/@clerk/types": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.6.0.tgz",
"integrity": "sha512-kowqVGqLfu0Zl2Pteum70MfkGHqBUoHHeR+u2+yWVl1lKHLCiyY1u8ntYBEIolAylBaQNDuRzxyMIDPSxjPE8g==",
"dependencies": {
"csstype": "3.1.1"
},
"engines": {
"node": ">=18.17.0"
}
},
"node_modules/@clerk/types/node_modules/csstype": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"node_modules/@esbuild-kit/core-utils": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz",
@@ -1027,18 +1148,18 @@
"integrity": "sha512-SwPWfeRa5veb1hOIBMdzI+73te5puUBHmqqaF1Bu7FjvxlYSz/kJcZKSa9Cg60zL0uRNeJL2SbRxV6Jp6Q1nFQ=="
},
"node_modules/@hono/node-server": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.11.1.tgz",
"integrity": "sha512-GW1Iomhmm1o4Z+X57xGby8A35Cu9UZLL7pSMdqDBkD99U5cywff8F+8hLk5aBTzNubnsFAvWQ/fZjNwPsEn9lA==",
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.11.3.tgz",
"integrity": "sha512-mFg3qlKkDtMWSalX5Gyh6Zd3MXay0biGobFlyJ49i6R1smBBS1CYkNZbvwLlw+4sSrHO4ZiH7kj4TcLpl2Jr3g==",
"dev": true,
"engines": {
"node": ">=18.14.1"
}
},
"node_modules/@hono/zod-validator": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.2.1.tgz",
"integrity": "sha512-HFoxln7Q6JsE64qz2WBS28SD33UB2alp3aRKmcWnNLDzEL1BLsWfbdX6e1HIiUprHYTIXf5y7ax8eYidKUwyaA==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.2.2.tgz",
"integrity": "sha512-dSDxaPV70Py8wuIU2QNpoVEIOSzSXZ/6/B/h4xA7eOMz7+AarKTSGV8E6QwrdcCbBLkpqfJ4Q2TmBO0eP1tCBQ==",
"dev": true,
"peerDependencies": {
"hono": ">=3.9.0",
@@ -3030,11 +3151,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -3296,6 +3417,11 @@
"node": ">= 8"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -3509,6 +3635,15 @@
"node": ">=6.0.0"
}
},
"node_modules/dot-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/dreamopt": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz",
@@ -3522,9 +3657,9 @@
}
},
"node_modules/drizzle-kit": {
"version": "0.20.17",
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.17.tgz",
"integrity": "sha512-mLVDS4nXmO09wFVlzGrdshWnAL+U9eQGC5zRs6hTN6Q9arwQGWU2XnZ17I8BM8Quau8CQRx3Ms6VPgRWJFVp7Q==",
"version": "0.20.18",
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.18.tgz",
"integrity": "sha512-fLTwcnLqtBxGd+51H/dEm9TC0FW6+cIX/RVPyNcitBO77X9+nkogEfMAJebpd/8Yl4KucmePHRYRWWvUlW0rqg==",
"dev": true,
"dependencies": {
"@esbuild-kit/esm-loader": "^2.5.5",
@@ -4725,9 +4860,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -4933,6 +5068,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -4959,6 +5095,11 @@
"node": ">=10.13.0"
}
},
"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=="
},
"node_modules/glob/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
@@ -5142,9 +5283,9 @@
"dev": true
},
"node_modules/hono": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.3.2.tgz",
"integrity": "sha512-wiZcF5N06tc232U11DnqW6hP8DNoypjsrxslKXfvOqOAkTdh7K1HLZJH/92Mf+urxUTGi96f1w4xx/1Qozoqiw==",
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.4.6.tgz",
"integrity": "sha512-XGRnoH8WONv60+PPvP9Sn067A9r/8JdHDJ5bgon0DVEHeR1cJPkWjv2aT+DBfMH9/mEkYa1+VEVFp1DT1lIwjw==",
"dev": true,
"engines": {
"node": ">=16.0.0"
@@ -5657,6 +5798,14 @@
"url": "https://github.com/sponsors/panva"
}
},
"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==",
"engines": {
"node": ">=14"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5831,10 +5980,19 @@
"loose-envify": "cli.js"
}
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dependencies": {
"tslib": "^2.0.3"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@@ -5851,20 +6009,34 @@
"es5-ext": "~0.10.2"
}
},
"node_modules/map-obj": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/memoizee": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
"integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
"version": "0.4.17",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz",
"integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==",
"dev": true,
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.53",
"d": "^1.0.2",
"es5-ext": "^0.10.64",
"es6-weak-map": "^2.0.3",
"event-emitter": "^0.3.5",
"is-promise": "^2.2.2",
"lru-queue": "^0.1.0",
"next-tick": "^1.1.0",
"timers-ext": "^0.1.7"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/merge2": {
@@ -6006,49 +6178,6 @@
}
}
},
"node_modules/next-auth": {
"version": "4.24.7",
"resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.7.tgz",
"integrity": "sha512-iChjE8ov/1K/z98gdKbn2Jw+2vLgJtVV39X+rCP5SGnVQuco7QOr19FRNGMIrD8d3LYhHWV9j9sKLzq1aDWWQQ==",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@panva/hkdf": "^1.0.2",
"cookie": "^0.5.0",
"jose": "^4.15.5",
"oauth": "^0.9.15",
"openid-client": "^5.4.0",
"preact": "^10.6.3",
"preact-render-to-string": "^5.1.19",
"uuid": "^8.3.2"
},
"peerDependencies": {
"next": "^12.2.5 || ^13 || ^14",
"nodemailer": "^6.6.5",
"react": "^17.0.2 || ^18",
"react-dom": "^17.0.2 || ^18"
},
"peerDependenciesMeta": {
"nodemailer": {
"optional": true
}
}
},
"node_modules/next-auth/node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/next-auth/node_modules/jose": {
"version": "4.15.5",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz",
"integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/next-themes": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
@@ -6091,6 +6220,15 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
}
},
"node_modules/node-gyp-build": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
@@ -6109,11 +6247,6 @@
"node": ">=0.10.0"
}
},
"node_modules/oauth": {
"version": "0.9.15",
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
"integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="
},
"node_modules/oauth4webapi": {
"version": "2.10.4",
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.10.4.tgz",
@@ -6130,14 +6263,6 @@
"node": ">=0.10.0"
}
},
"node_modules/object-hash": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
"engines": {
"node": ">= 6"
}
},
"node_modules/object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -6254,14 +6379,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/oidc-token-hash": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
"integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
"engines": {
"node": "^10.13.0 || >=12.0.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -6271,28 +6388,6 @@
"wrappy": "1"
}
},
"node_modules/openid-client": {
"version": "5.6.5",
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz",
"integrity": "sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==",
"dependencies": {
"jose": "^4.15.5",
"lru-cache": "^6.0.0",
"object-hash": "^2.2.0",
"oidc-token-hash": "^5.0.3"
},
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/openid-client/node_modules/jose": {
"version": "4.15.5",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz",
"integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -6406,6 +6501,11 @@
"node": "14 || >=16.14"
}
},
"node_modules/path-to-regexp": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
"integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw=="
},
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -7367,6 +7467,39 @@
"node": ">=8"
}
},
"node_modules/snake-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
"dependencies": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/snakecase-keys": {
"version": "5.4.4",
"resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.4.4.tgz",
"integrity": "sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==",
"dependencies": {
"map-obj": "^4.1.0",
"snake-case": "^3.0.4",
"type-fest": "^2.5.2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/snakecase-keys/node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sonner": {
"version": "1.4.41",
"resolved": "https://registry.npmjs.org/sonner/-/sonner-1.4.41.tgz",
@@ -7412,6 +7545,11 @@
"node": ">= 10.x"
}
},
"node_modules/std-env": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
"integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg=="
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -7705,6 +7843,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/swr": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz",
"integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==",
"dependencies": {
"client-only": "^0.0.1",
"use-sync-external-store": "^1.2.0"
},
"peerDependencies": {
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/tailwind-merge": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz",
@@ -7804,13 +7954,16 @@
}
},
"node_modules/timers-ext": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
"integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz",
"integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==",
"dev": true,
"dependencies": {
"es5-ext": "~0.10.46",
"next-tick": "1"
"es5-ext": "^0.10.64",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/to-regex-range": {
@@ -7859,9 +8012,9 @@
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/type": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==",
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
"integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
"dev": true
},
"node_modules/type-check": {
@@ -8069,14 +8222,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -8312,7 +8457,8 @@
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yaml": {
"version": "2.4.2",

View File

@@ -13,6 +13,7 @@
},
"dependencies": {
"@auth/drizzle-adapter": "^0.7.0",
"@clerk/nextjs": "^5.1.5",
"@formkit/auto-animate": "^0.8.2",
"@hookform/resolvers": "^3.4.2",
"@radix-ui/react-accordion": "^1.1.2",
@@ -39,7 +40,6 @@
"lodash.debounce": "^4.0.8",
"lodash.merge": "^4.6.2",
"next": "^14.2.1",
"next-auth": "^4.24.6",
"next-themes": "^0.3.0",
"postgres": "^3.4.3",
"react": "18.2.0",

View File

@@ -0,0 +1,9 @@
import { SignIn } from "@clerk/nextjs";
export default function Page() {
return (
<div className="flex justify-center py-24">
<SignIn />
</div>
);
}

View File

@@ -0,0 +1,9 @@
import { SignUp } from "@clerk/nextjs";
export default function Page() {
return (
<div className="flex justify-center py-24">
<SignUp />
</div>
);
}

View File

@@ -5,6 +5,7 @@ import { LuFeather, LuGithub, LuMoon } from "react-icons/lu";
import { toast } from "sonner";
import { Button } from "~/components/ui/button";
import { CTA_LINK } from "~/lib/constants";
import { useAuth, useUser } from "@clerk/nextjs";
const HEADER_LINKS = [
{ label: "About", url: "#about" },
@@ -14,6 +15,9 @@ const HEADER_LINKS = [
];
export const Header: React.FC = () => {
const { signOut } = useAuth();
const { isLoaded, isSignedIn, user } = useUser();
return (
<header className="sticky left-0 right-0 top-0 z-40 bg-white font-mono font-medium shadow-2xl transition-all duration-300 ease-in-out">
<div className="mx-auto flex max-w-7xl flex-row justify-between gap-x-4 p-4">
@@ -56,10 +60,17 @@ export const Header: React.FC = () => {
</Button>
</div>
{/* CTA */}
<Button asChild>
<Link href={CTA_LINK}>Sign Up</Link>
</Button>
{isLoaded && isSignedIn ? (
<>
<Button onClick={() => signOut()}>Sign Out</Button>
<p>Logged in as {user?.fullName}</p>
</>
) : (
/* CTA */
<Button asChild>
<Link href={CTA_LINK}>Sign Up</Link>
</Button>
)}
</nav>
</div>
</header>

View File

@@ -1,7 +0,0 @@
import NextAuth from "next-auth";
import { authOptions } from "~/server/auth";
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

View File

@@ -1,3 +1,4 @@
import { getAuth } from "@clerk/nextjs/server";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { type NextRequest } from "next/server";
@@ -11,7 +12,7 @@ import { createTRPCContext } from "~/server/api/trpc";
*/
const createContext = async (req: NextRequest) => {
return createTRPCContext({
headers: req.headers,
auth: getAuth(req),
});
};
@@ -25,7 +26,7 @@ const handler = (req: NextRequest) =>
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,

View File

@@ -2,6 +2,7 @@ import "~/styles/globals.css";
import { Spline_Sans_Mono, Montserrat } from "next/font/google";
import { type PropsWithChildren } from "react";
import { ClerkProvider } from "@clerk/nextjs";
import { TRPCReactProvider } from "~/trpc/react";
import { Toaster } from "~/components/ui/sonner";
@@ -29,13 +30,15 @@ export const metadata = {
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="en" className="scroll-smooth">
<body
className={`font-sans ${montserrat.variable} ${splineSansMono.variable} text-neutral-950 selection:bg-primary-500 selection:text-neutral-50`}
>
<TRPCReactProvider>{children}</TRPCReactProvider>
<Toaster />
</body>
</html>
<ClerkProvider>
<html lang="en" className="scroll-smooth">
<body
className={`font-sans ${montserrat.variable} ${splineSansMono.variable} text-neutral-950 selection:bg-primary-500 selection:text-neutral-50`}
>
<TRPCReactProvider>{children}</TRPCReactProvider>
<Toaster />
</body>
</html>
</ClerkProvider>
);
}

View File

@@ -11,19 +11,7 @@ export const env = createEnv({
NODE_ENV: z
.enum(["development", "test", "production"])
.default("development"),
NEXTAUTH_SECRET:
process.env.NODE_ENV === "production"
? z.string()
: z.string().optional(),
NEXTAUTH_URL: z.preprocess(
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
// Since NextAuth.js automatically uses the VERCEL_URL if present.
(str) => process.env.VERCEL_URL ?? str,
// VERCEL_URL doesn't include `https` so it cant be validated as a URL
process.env.VERCEL ? z.string() : z.string().url(),
),
// DISCORD_CLIENT_ID: z.string(),
// DISCORD_CLIENT_SECRET: z.string(),
CLERK_SECRET_KEY: z.string(),
},
/**
@@ -32,7 +20,7 @@ export const env = createEnv({
* `NEXT_PUBLIC_`.
*/
client: {
// NEXT_PUBLIC_CLIENTVAR: z.string(),
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string(),
},
/**
@@ -42,10 +30,9 @@ export const env = createEnv({
runtimeEnv: {
POSTGRES_URL: process.env.POSTGRES_URL,
NODE_ENV: process.env.NODE_ENV,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
// DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID,
// DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET,
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially

11
src/middleware.ts Normal file
View File

@@ -0,0 +1,11 @@
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isProtectedRoute = createRouteMatcher(["/cv(.*)", "/resume(.*)"]);
export default clerkMiddleware((auth, req) => {
if (isProtectedRoute(req)) auth().protect();
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};

View File

@@ -7,11 +7,11 @@
* need to use are documented accordingly near the end.
*/
import { getAuth } from "@clerk/nextjs/server";
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";
import { getServerAuthSession } from "~/server/auth";
import { db } from "~/server/db";
/**
@@ -26,12 +26,11 @@ import { db } from "~/server/db";
*
* @see https://trpc.io/docs/server/context
*/
export const createTRPCContext = async (opts: { headers: Headers }) => {
const session = await getServerAuthSession();
export const createTRPCContext = async (opts: {
auth: ReturnType<typeof getAuth>;
}) => {
return {
db,
session,
...opts,
};
};
@@ -96,13 +95,13 @@ export const publicProcedure = t.procedure;
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
if (!ctx.auth?.userId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
// infers the `auth` as non-nullable
auth: { ...ctx.auth, userId: ctx.auth.userId },
},
});
});

View File

@@ -1,71 +0,0 @@
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import {
getServerSession,
type DefaultSession,
type NextAuthOptions,
} from "next-auth";
import { type Adapter } from "next-auth/adapters";
import { db } from "~/server/db";
import { createTable } from "~/server/db/schema";
/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
* object and keep type safety.
*
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
*/
declare module "next-auth" {
interface Session extends DefaultSession {
user: {
id: string;
// ...other properties
// role: UserRole;
} & DefaultSession["user"];
}
// interface User {
// // ...other properties
// // role: UserRole;
// }
}
/**
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
*
* @see https://next-auth.js.org/configuration/options
*/
export const authOptions: NextAuthOptions = {
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
},
}),
},
adapter: DrizzleAdapter(db, createTable) as Adapter,
providers: [
// DiscordProvider({
// clientId: env.DISCORD_CLIENT_ID,
// clientSecret: env.DISCORD_CLIENT_SECRET,
// }),
/**
* ...add more providers here.
*
* Most other providers require a bit more work than the Discord provider. For example, the
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
*
* @see https://next-auth.js.org/providers/github
*/
],
};
/**
* Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
*
* @see https://next-auth.js.org/configuration/nextjs
*/
export const getServerAuthSession = () => getServerSession(authOptions);

View File

@@ -1,14 +1,5 @@
import { pgTableCreator } from "drizzle-orm/pg-core";
import { relations, sql } from "drizzle-orm";
import {
index,
integer,
primaryKey,
text,
timestamp,
varchar,
} from "drizzle-orm/pg-core";
import { type AdapterAccount } from "next-auth/adapters";
import { varchar } from "drizzle-orm/pg-core";
/**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
@@ -17,80 +8,3 @@ import { type AdapterAccount } from "next-auth/adapters";
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema
*/
export const createTable = pgTableCreator((name) => `resume-factory_${name}`);
export const users = createTable("user", {
id: varchar("id", { length: 255 }).notNull().primaryKey(),
name: varchar("name", { length: 255 }),
email: varchar("email", { length: 255 }).notNull(),
emailVerified: timestamp("emailVerified", {
mode: "date",
}).default(sql`CURRENT_TIMESTAMP`),
image: varchar("image", { length: 255 }),
});
export const usersRelations = relations(users, ({ many }) => ({
accounts: many(accounts),
}));
export const accounts = createTable(
"account",
{
userId: varchar("userId", { length: 255 })
.notNull()
.references(() => users.id),
type: varchar("type", { length: 255 })
.$type<AdapterAccount["type"]>()
.notNull(),
provider: varchar("provider", { length: 255 }).notNull(),
providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
refresh_token: text("refresh_token"),
access_token: text("access_token"),
expires_at: integer("expires_at"),
token_type: varchar("token_type", { length: 255 }),
scope: varchar("scope", { length: 255 }),
id_token: text("id_token"),
session_state: varchar("session_state", { length: 255 }),
},
(account) => ({
compoundKey: primaryKey({
columns: [account.provider, account.providerAccountId],
}),
userIdIdx: index("account_userId_idx").on(account.userId),
}),
);
export const accountsRelations = relations(accounts, ({ one }) => ({
user: one(users, { fields: [accounts.userId], references: [users.id] }),
}));
export const sessions = createTable(
"session",
{
sessionToken: varchar("sessionToken", { length: 255 })
.notNull()
.primaryKey(),
userId: varchar("userId", { length: 255 })
.notNull()
.references(() => users.id),
expires: timestamp("expires", { mode: "date" }).notNull(),
},
(session) => ({
userIdIdx: index("session_userId_idx").on(session.userId),
}),
);
export const sessionsRelations = relations(sessions, ({ one }) => ({
user: one(users, { fields: [sessions.userId], references: [users.id] }),
}));
export const verificationTokens = createTable(
"verificationToken",
{
identifier: varchar("identifier", { length: 255 }).notNull(),
token: varchar("token", { length: 255 }).notNull(),
expires: timestamp("expires", { mode: "date" }).notNull(),
},
(vt) => ({
compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }),
}),
);

View File

@@ -1,21 +1,18 @@
import "server-only";
import { headers } from "next/headers";
import { cache } from "react";
import { createCaller } from "~/server/api/root";
import { createTRPCContext } from "~/server/api/trpc";
import { auth } from "@clerk/nextjs/server";
/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a tRPC call from a React Server Component.
*/
const createContext = cache(() => {
const heads = new Headers(headers());
heads.set("x-trpc-source", "rsc");
return createTRPCContext({
headers: heads,
auth: auth(),
});
});