mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
31 Commits
@auth/core
...
@auth/core
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7842077ec | ||
|
|
b2e5b9f6a8 | ||
|
|
0681531627 | ||
|
|
ea81c467e9 | ||
|
|
bf2835d38f | ||
|
|
89d230666b | ||
|
|
f86e56f78a | ||
|
|
fe20b943ae | ||
|
|
4678c4d4fc | ||
|
|
3eb3f8f107 | ||
|
|
7fd03f38e3 | ||
|
|
ae44b72765 | ||
|
|
a996ab57e8 | ||
|
|
ebdeaf740d | ||
|
|
c5c8a81462 | ||
|
|
61d30f3dcd | ||
|
|
a9180a752b | ||
|
|
6c4180146e | ||
|
|
ec6c4ea2be | ||
|
|
3dfc86334e | ||
|
|
01d6019638 | ||
|
|
4730429a9f | ||
|
|
a49236ef62 | ||
|
|
96ade948ef | ||
|
|
550507b2d1 | ||
|
|
1eddcf643c | ||
|
|
17d71a04d6 | ||
|
|
3c65e264af | ||
|
|
28d8d4894d | ||
|
|
c6b98a8f08 | ||
|
|
d042f933c6 |
3
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
3
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -22,9 +22,12 @@ body:
|
||||
options:
|
||||
- "Custom adapter"
|
||||
- "@auth/dgraph-adapter"
|
||||
- "@auth/drizzle-adapter"
|
||||
- "@auth/dynamodb-adapter"
|
||||
- "@auth/drizzle-adapter"
|
||||
- "@auth/fauna-adapter"
|
||||
- "@auth/firebase-adapter"
|
||||
- "@auth/kysely-adapter"
|
||||
- "@auth/mikro-orm-adapter"
|
||||
- "@auth/mongodb-adapter"
|
||||
- "@auth/neo4j-adapter"
|
||||
|
||||
6
.github/issue-labeler.yml
vendored
6
.github/issue-labeler.yml
vendored
@@ -3,6 +3,9 @@
|
||||
dgraph:
|
||||
- "@auth/dgraph-adapter"
|
||||
|
||||
drizzle:
|
||||
- "@auth/drizzle-adapter"
|
||||
|
||||
dynamodb:
|
||||
- "@auth/dynamodb-adapter"
|
||||
|
||||
@@ -12,6 +15,9 @@ fauna:
|
||||
firebase:
|
||||
- "@auth/firebase-adapter"
|
||||
|
||||
kysely:
|
||||
- "@auth/kysely-adapter"
|
||||
|
||||
mikro-orm:
|
||||
- "@auth/mikro-orm-adapter"
|
||||
|
||||
|
||||
1
.github/pr-labeler.yml
vendored
1
.github/pr-labeler.yml
vendored
@@ -15,6 +15,7 @@ neo4j: ["packages/adapter-neo4j/**/*"]
|
||||
playgrounds: ["apps/playgrounds/**/*"]
|
||||
pouchdb: ["packages/adapter-pouchdb/**/*"]
|
||||
prisma: ["packages/adapter-prisma/**/*"]
|
||||
kysely: ["packages/adapter-kysely/**/*"]
|
||||
providers: ["packages/core/src/providers/**/*"]
|
||||
sequelize: ["packages/adapter-sequelize/**/*"]
|
||||
solidjs: ["packages/frameworks-solid-start/**/*"]
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -57,6 +57,8 @@ on:
|
||||
- "adapter-xata"
|
||||
- "next-auth"
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
FORCE_COLOR: true
|
||||
|
||||
jobs:
|
||||
@@ -79,22 +81,12 @@ jobs:
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
|
||||
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
- name: Upload Turbo artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: turbo-report
|
||||
path: .turbo/runs/
|
||||
# - name: Run E2E tests
|
||||
# if: github.repository == 'nextauthjs/next-auth'
|
||||
# run: pnpm e2e
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,8 @@
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
packages/*/.npmrc
|
||||
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
|
||||
153
README.md
Normal file
153
README.md
Normal file
@@ -0,0 +1,153 @@
|
||||
<p align="center">
|
||||
<br/>
|
||||
<a href="https://authjs.dev" target="_blank"><img width="96px" src="https://authjs.dev/img/logo/logo-sm.png" /></a>
|
||||
<h3 align="center">Auth.js</h3>
|
||||
<p align="center">Authentication for the Web.</p>
|
||||
<p align="center">Open Source. Full Stack. Own Your Data.</p>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/next-auth">
|
||||
<img src="https://img.shields.io/npm/dm/next-auth?style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/next-auth">
|
||||
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?label=latest&style=flat-square" alt="Github Stable Release" />
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
Auth.js is a set of open-source packages that are built on Web Standard APIs for authentication in modern applications with any framework on any platform in any JS runtime.
|
||||
|
||||
See [authjs.dev](https://authjs.dev) for our framework-specific libraries, or check out [next-auth.js.org](https://next-auth.js.org) for `next-auth` (Next.js).
|
||||
|
||||
## Features
|
||||
|
||||
### Flexible and easy to use
|
||||
|
||||
- Designed to work with any OAuth service, it supports 2.0+, OIDC
|
||||
- Built-in support for [many popular sign-in services](https://github.com/nextauthjs/next-auth/tree/main/packages/core/src/providers)
|
||||
- Email/Passwordless authentication
|
||||
- Bring Your Database - or none! - stateless authentication with any backend (Active Directory, LDAP, etc.)
|
||||
- Runtime-agnostic, runs anywhere! (Vercel Edge Functions, Node.js, Serverless, etc.)
|
||||
|
||||
### Own your data
|
||||
|
||||
Auth.js can be used with or without a database.
|
||||
|
||||
- An open-source solution that allows you to keep control of your data
|
||||
- Built-in support for [MySQL, MariaDB, Postgres, Microsoft SQL Server, MongoDB, SQLite, etc.](https://adapters.authjs.dev)
|
||||
- Works great with databases from popular hosting providers
|
||||
|
||||
### Secure by default
|
||||
|
||||
- Promotes the use of passwordless sign-in mechanisms
|
||||
- Designed to be secure by default and encourage best practices for safeguarding user data
|
||||
- Uses Cross-Site Request Forgery (CSRF) Tokens on POST routes (sign in, sign out)
|
||||
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
|
||||
- When JSON Web Tokens are used, they are encrypted by default (JWE) with A256GCM
|
||||
- Features tab/window syncing and session polling to support short-lived sessions
|
||||
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org)
|
||||
|
||||
Advanced configuration allows you to define your routines to handle controlling what accounts are allowed to sign in, for encoding and decoding JSON Web Tokens and to set custom cookie security policies and session properties, so you can control who can sign in and how often sessions have to be re-validated.
|
||||
|
||||
### TypeScript
|
||||
|
||||
Auth.js libraries are written with type safety in mind. [Check out the docs](https://authjs.dev/getting-started/typescript) for more information.
|
||||
|
||||
## Security
|
||||
|
||||
If you think you have found a vulnerability (or are not sure) in Auth.js or any of the related packages (i.e. Adapters), we ask you to read our [Security Policy](https://authjs.dev/security) to reach out responsibly. Please do not open Pull Requests/Issues/Discussions before consulting with us.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
[Auth.js is made possible thanks to all of its contributors.](https://authjs.dev/contributors)
|
||||
|
||||
<a href="https://github.com/nextauthjs/next-auth/graphs/contributors">
|
||||
<img width="500px" src="https://contrib.rocks/image?repo=nextauthjs/next-auth" />
|
||||
</a>
|
||||
<div>
|
||||
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss"></a>
|
||||
</div>
|
||||
|
||||
### Support
|
||||
|
||||
We have an [OpenCollective](https://opencollective.com/nextauth) for individuals and companies looking to contribute financially to the project!
|
||||
|
||||
<!--sponsors start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://vercel.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/14985020?v=4" alt="Vercel Logo" />
|
||||
</a><br />
|
||||
<div>Vercel</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor <br /> ☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://prisma.io" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/17219288?v=4" alt="Prisma Logo" />
|
||||
</a><br />
|
||||
<div>Prisma</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://clerk.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/49538330?s=200&v=4" alt="Clerk Logo" />
|
||||
</a><br />
|
||||
<div>Clerk</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://lowdefy.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/47087496?s=200&v=4" alt="Lowdefy Logo" />
|
||||
</a><br />
|
||||
<div>Lowdefy</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://workos.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/47638084?s=200&v=4" alt="WorkOS Logo" />
|
||||
</a><br />
|
||||
<div>WorkOS</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://www.descope.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/97479186?v=4" alt="Descope Logo" />
|
||||
</a><br />
|
||||
<div>Descope</div><br />
|
||||
<sub>🥉 Bronze Financial Sponsor</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://checklyhq.com" target="_blank">
|
||||
<img width="128px" src="https://avatars.githubusercontent.com/u/25982255?v=4" alt="Checkly Logo" />
|
||||
</a><br />
|
||||
<div>Checkly</div><br />
|
||||
<sub>☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
<td align="center" valign="top">
|
||||
<a href="https://superblog.ai/" target="_blank">
|
||||
<img width="128px" src="https://d33wubrfki0l68.cloudfront.net/cdc4a3833bd878933fcc131655878dbf226ac1c5/10cd6/images/logo_bolt_small.png" alt="superblog Logo" />
|
||||
</a><br />
|
||||
<div>superblog</div><br />
|
||||
<sub>☁️ Infrastructure Support</sub>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<!--sponsors end-->
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please first read
|
||||
our [Contributing Guide](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
ISC
|
||||
@@ -25,6 +25,10 @@ Using an Auth.js / NextAuth.js adapter you can connect to any database service o
|
||||
<img src="/img/adapters/firebase.svg" width="40" />
|
||||
<h4 class="adapter-card__title">Firebase Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/kysely" class="adapter-card">
|
||||
<img src="/img/adapters/kysely.svg" width="40" />
|
||||
<h4 class="adapter-card__title">Kysely Adapter</h4>
|
||||
</a>
|
||||
<a href="/reference/adapter/mikro-orm" class="adapter-card">
|
||||
<img src="/img/adapters/mikro-orm.png" width="30" />
|
||||
<h4 class="adapter-card__title">Mikro ORM Adapter</h4>
|
||||
|
||||
@@ -269,6 +269,7 @@ const docusaurusConfig = {
|
||||
typedocAdapter("DynamoDB"),
|
||||
typedocAdapter("Fauna"),
|
||||
typedocAdapter("Firebase"),
|
||||
typedocAdapter("Kysely"),
|
||||
typedocAdapter("Mikro ORM"),
|
||||
typedocAdapter("MongoDB"),
|
||||
typedocAdapter("Neo4j"),
|
||||
|
||||
@@ -59,6 +59,7 @@ module.exports = {
|
||||
{ type: "doc", id: "reference/adapter/dynamodb/index" },
|
||||
{ type: "doc", id: "reference/adapter/fauna/index" },
|
||||
{ type: "doc", id: "reference/adapter/firebase/index" },
|
||||
{ type: "doc", id: "reference/adapter/kysely/index" },
|
||||
{ type: "doc", id: "reference/adapter/mikro-orm/index" },
|
||||
{ type: "doc", id: "reference/adapter/mongodb/index" },
|
||||
{ type: "doc", id: "reference/adapter/neo4j/index" },
|
||||
|
||||
14
docs/static/img/adapters/kysely.svg
vendored
Normal file
14
docs/static/img/adapters/kysely.svg
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg width="132" height="132" viewBox="0 0 132 132" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_8_3)">
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" fill="white" />
|
||||
<path
|
||||
d="M41.2983 109V23.9091H46.4918V73.31H47.0735L91.9457 23.9091H98.8427L61.9062 64.1694L98.5103 109H92.0288L58.5824 67.9087L46.4918 81.2873V109H41.2983Z"
|
||||
fill="black" />
|
||||
</g>
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" stroke="#121212" stroke-width="4" />
|
||||
<defs>
|
||||
<clipPath id="clip0_8_3">
|
||||
<rect x="2" y="2" width="128" height="128" rx="16" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 637 B |
11
docs/static/img/providers/passage.svg
vendored
Normal file
11
docs/static/img/providers/passage.svg
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.8" d="M37.8419 71.6921L65.1425 87.4541C86.2537 99.6426 93.4921 126.639 81.3036 147.75C80.2315 149.607 79.045 151.353 77.7583 152.989L12.6182 115.381C8.67588 113.105 5.58417 109.922 3.44179 106.254C-0.964934 98.6912 -1.30613 89.0446 3.38448 80.9202C10.348 68.8591 25.7752 64.7254 37.8419 71.6921Z" fill="#3D53F6"/>
|
||||
<path opacity="0.5" d="M37.8419 180.052L65.1425 164.29C86.2537 152.101 93.4921 125.105 81.3036 103.994C80.2315 102.137 79.045 100.391 77.7583 98.7544L12.6182 136.363C8.67588 138.639 5.58417 141.822 3.44179 145.49C-0.964934 153.053 -1.30613 162.699 3.38448 170.824C10.348 182.885 25.7752 187.019 37.8419 180.052Z" fill="#3D53F6"/>
|
||||
<path opacity="0.5" d="M212.753 71.6921L185.452 87.4541C164.341 99.6426 157.103 126.639 169.291 147.75C170.363 149.607 171.55 151.353 172.836 152.989L237.976 115.381C241.919 113.105 245.01 109.922 247.153 106.254C251.56 98.6912 251.901 89.0446 247.21 80.9202C240.247 68.8591 224.819 64.7254 212.753 71.6921Z" fill="#3D53F6"/>
|
||||
<path opacity="0.8" d="M212.753 180.052L185.452 164.29C164.341 152.101 157.103 125.105 169.291 103.994C170.363 102.137 171.55 100.391 172.836 98.7544L237.976 136.363C241.919 138.639 245.01 141.822 247.153 145.49C251.56 153.053 251.901 162.699 247.21 170.824C240.247 182.885 224.819 187.019 212.753 180.052Z" fill="#3D53F6"/>
|
||||
<path d="M125.297 150.525C139.228 150.525 150.52 139.232 150.52 125.302C150.52 111.372 139.228 100.079 125.297 100.079C111.367 100.079 100.075 111.372 100.075 125.302C100.075 139.232 111.367 150.525 125.297 150.525Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.8" d="M71.1172 212.753L86.8793 185.452C99.0678 164.341 126.064 157.102 147.175 169.291C149.032 170.363 150.778 171.55 152.415 172.836L114.806 237.976C112.53 241.919 109.347 245.01 105.679 247.153C98.1164 251.559 88.4698 251.901 80.3454 247.21C68.2842 240.247 64.1505 224.819 71.1172 212.753Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.5" d="M179.477 212.752L163.715 185.452C151.526 164.341 124.53 157.102 103.419 169.291C101.562 170.363 99.8157 171.549 98.1794 172.836L135.788 237.976C138.064 241.919 141.247 245.01 144.915 247.153C152.478 251.559 162.124 251.901 170.249 247.21C182.31 240.246 186.444 224.819 179.477 212.752Z" fill="#FF2F1D"/>
|
||||
<path opacity="0.5" d="M71.1172 37.8419L86.8793 65.1425C99.0678 86.2537 126.064 93.4921 147.175 81.3036C149.032 80.2315 150.778 79.045 152.415 77.7583L114.806 12.6182C112.53 8.67589 109.347 5.58416 105.679 3.44179C98.1164 -0.964936 88.4698 -1.30613 80.3454 3.38449C68.2842 10.348 64.1505 25.7752 71.1172 37.8419Z" fill="#3D53F6"/>
|
||||
<path opacity="0.8" d="M179.477 37.8419L163.715 65.1425C151.526 86.2537 124.53 93.4921 103.419 81.3036C101.562 80.2315 99.8157 79.045 98.1794 77.7583L135.788 12.6182C138.064 8.67589 141.247 5.58416 144.915 3.44179C152.478 -0.964936 162.124 -1.30613 170.249 3.38449C182.31 10.348 186.444 25.7752 179.477 37.8419Z" fill="#3D53F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||
"cleanUrls": true,
|
||||
"headers": [
|
||||
{
|
||||
@@ -76,10 +77,15 @@
|
||||
"has": [{ "type": "host", "value": "warnings.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/warnings/:path*"
|
||||
},
|
||||
{
|
||||
"source": "/",
|
||||
"has": [{ "type": "host", "value": "adapters.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/adapters"
|
||||
},
|
||||
{
|
||||
"source": "/:path(.*)",
|
||||
"has": [{ "type": "host", "value": "adapters.authjs.dev" }],
|
||||
"destination": "https://authjs.dev/reference/adapters/:path*"
|
||||
"destination": "https://authjs.dev/reference/adapter/:path*"
|
||||
},
|
||||
{
|
||||
"source": "/:path",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -4,7 +4,7 @@
|
||||
<img height="64px" src="https://authjs.dev/img/logo/logo-sm.png" />
|
||||
</a>
|
||||
<a href="https://github.com/drizzle-team/drizzle-orm" target="_blank">
|
||||
<img height="64px" src="https://pbs.twimg.com/profile_images/1598308842391179266/CtXrfLnk_400x400.jpg"/>
|
||||
<img height="64px" src="https://authjs.dev/img/adapters/drizzle-orm.png"/>
|
||||
</a>
|
||||
<h3 align="center"><b>Drizzle ORM Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/drizzle-adapter",
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.0",
|
||||
"description": "Drizzle adapter for Auth.js.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
* @module @auth/drizzle-adapter
|
||||
*/
|
||||
|
||||
import { MySqlTableFn } from "drizzle-orm/mysql-core/index.js"
|
||||
import { PgTableFn } from "drizzle-orm/pg-core/index.js"
|
||||
import { SQLiteTableFn } from "drizzle-orm/sqlite-core/index.js"
|
||||
import { mySqlDrizzleAdapter } from "./lib/mysql.js"
|
||||
import { pgDrizzleAdapter } from "./lib/pg.js"
|
||||
import { SQLiteDrizzleAdapter } from "./lib/sqlite.js"
|
||||
@@ -24,12 +27,13 @@ import {
|
||||
isPgDatabase,
|
||||
isSQLiteDatabase,
|
||||
SqlFlavorOptions,
|
||||
TableFn,
|
||||
} from "./lib/utils.js"
|
||||
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
|
||||
/**
|
||||
* Add the adapter to your `app/api/[...nextauth]/route.js` next-auth configuration object.
|
||||
* Add the adapter to your `pages/api/[...nextauth].ts` next-auth configuration object.
|
||||
*
|
||||
* ```ts title="pages/api/auth/[...nextauth].ts"
|
||||
* import NextAuth from "next-auth"
|
||||
@@ -47,6 +51,10 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* ],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* :::info
|
||||
* If you're using multi-project schemas, you can pass your table function as a second argument
|
||||
* :::
|
||||
*
|
||||
* ## Setup
|
||||
*
|
||||
@@ -69,7 +77,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* } from "drizzle-orm/pg-core"
|
||||
* import type { AdapterAccount } from '@auth/core/adapters'
|
||||
*
|
||||
* export const users = pgTable("users", {
|
||||
* export const users = pgTable("user", {
|
||||
* id: text("id").notNull().primaryKey(),
|
||||
* name: text("name"),
|
||||
* email: text("email").notNull(),
|
||||
@@ -78,7 +86,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
*
|
||||
* export const accounts = pgTable(
|
||||
* "accounts",
|
||||
* "account",
|
||||
* {
|
||||
* userId: text("userId")
|
||||
* .notNull()
|
||||
@@ -99,7 +107,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
* )
|
||||
*
|
||||
* export const sessions = pgTable("sessions", {
|
||||
* export const sessions = pgTable("session", {
|
||||
* sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
* userId: text("userId")
|
||||
* .notNull()
|
||||
@@ -132,7 +140,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* } from "drizzle-orm/mysql-core"
|
||||
* import type { AdapterAccount } from "@auth/core/adapters"
|
||||
*
|
||||
* export const users = mysqlTable("users", {
|
||||
* export const users = mysqlTable("user", {
|
||||
* id: varchar("id", { length: 255 }).notNull().primaryKey(),
|
||||
* name: varchar("name", { length: 255 }),
|
||||
* email: varchar("email", { length: 255 }).notNull(),
|
||||
@@ -141,7 +149,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
*
|
||||
* export const accounts = mysqlTable(
|
||||
* "accounts",
|
||||
* "account",
|
||||
* {
|
||||
* userId: varchar("userId", { length: 255 })
|
||||
* .notNull()
|
||||
@@ -162,7 +170,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
* )
|
||||
*
|
||||
* export const sessions = mysqlTable("sessions", {
|
||||
* export const sessions = mysqlTable("session", {
|
||||
* sessionToken: varchar("sessionToken", { length: 255 }).notNull().primaryKey(),
|
||||
* userId: varchar("userId", { length: 255 })
|
||||
* .notNull()
|
||||
@@ -189,7 +197,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* import { integer, sqliteTable, text, primaryKey } from "drizzle-orm/sqlite-core"
|
||||
* import type { AdapterAccount } from "@auth/core/adapters"
|
||||
*
|
||||
* export const users = sqliteTable("users", {
|
||||
* export const users = sqliteTable("user", {
|
||||
* id: text("id").notNull().primaryKey(),
|
||||
* name: text("name"),
|
||||
* email: text("email").notNull(),
|
||||
@@ -198,7 +206,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
*
|
||||
* export const accounts = sqliteTable(
|
||||
* "accounts",
|
||||
* "account",
|
||||
* {
|
||||
* userId: text("userId")
|
||||
* .notNull()
|
||||
@@ -219,7 +227,7 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
* })
|
||||
* )
|
||||
*
|
||||
* export const sessions = sqliteTable("sessions", {
|
||||
* export const sessions = sqliteTable("session", {
|
||||
* sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
* userId: text("userId")
|
||||
* .notNull()
|
||||
@@ -249,19 +257,20 @@ import type { Adapter } from "@auth/core/adapters"
|
||||
*
|
||||
**/
|
||||
export function DrizzleAdapter<SqlFlavor extends SqlFlavorOptions>(
|
||||
db: SqlFlavor
|
||||
db: SqlFlavor,
|
||||
table?: TableFn<SqlFlavor>
|
||||
): Adapter {
|
||||
if (isMySqlDatabase(db)) {
|
||||
// We need to cast to unknown since the type overlaps (PScale is MySQL based)
|
||||
return mySqlDrizzleAdapter(db)
|
||||
return mySqlDrizzleAdapter(db, table as MySqlTableFn)
|
||||
}
|
||||
|
||||
if (isPgDatabase(db)) {
|
||||
return pgDrizzleAdapter(db)
|
||||
return pgDrizzleAdapter(db, table as PgTableFn)
|
||||
}
|
||||
|
||||
if (isSQLiteDatabase(db)) {
|
||||
return SQLiteDrizzleAdapter(db)
|
||||
return SQLiteDrizzleAdapter(db, table as SQLiteTableFn)
|
||||
}
|
||||
|
||||
throw new Error("Unsupported database type in Auth.js Drizzle adapter.")
|
||||
|
||||
@@ -2,75 +2,87 @@ import { and, eq } from "drizzle-orm"
|
||||
import {
|
||||
int,
|
||||
timestamp,
|
||||
mysqlTable,
|
||||
mysqlTable as defaultMySqlTableFn,
|
||||
primaryKey,
|
||||
varchar,
|
||||
MySqlTableFn,
|
||||
} from "drizzle-orm/mysql-core"
|
||||
|
||||
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
import type { MySql2Database } from "drizzle-orm/mysql2"
|
||||
|
||||
export const users = mysqlTable("users", {
|
||||
id: varchar("id", { length: 255 }).notNull().primaryKey(),
|
||||
name: varchar("name", { length: 255 }),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
emailVerified: timestamp("emailVerified", {
|
||||
mode: "date",
|
||||
fsp: 3,
|
||||
}).defaultNow(),
|
||||
image: varchar("image", { length: 255 }),
|
||||
})
|
||||
export function createTables(mySqlTable: MySqlTableFn) {
|
||||
const users = mySqlTable("user", {
|
||||
id: varchar("id", { length: 255 }).notNull().primaryKey(),
|
||||
name: varchar("name", { length: 255 }),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
emailVerified: timestamp("emailVerified", {
|
||||
mode: "date",
|
||||
fsp: 3,
|
||||
}).defaultNow(),
|
||||
image: varchar("image", { length: 255 }),
|
||||
})
|
||||
|
||||
export const accounts = mysqlTable(
|
||||
"accounts",
|
||||
{
|
||||
const accounts = mySqlTable(
|
||||
"account",
|
||||
{
|
||||
userId: varchar("userId", { length: 255 })
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: varchar("type", { length: 255 })
|
||||
.$type<AdapterAccount["type"]>()
|
||||
.notNull(),
|
||||
provider: varchar("provider", { length: 255 }).notNull(),
|
||||
providerAccountId: varchar("providerAccountId", {
|
||||
length: 255,
|
||||
}).notNull(),
|
||||
refresh_token: varchar("refresh_token", { length: 255 }),
|
||||
access_token: varchar("access_token", { length: 255 }),
|
||||
expires_at: int("expires_at"),
|
||||
token_type: varchar("token_type", { length: 255 }),
|
||||
scope: varchar("scope", { length: 255 }),
|
||||
id_token: varchar("id_token", { length: 255 }),
|
||||
session_state: varchar("session_state", { length: 255 }),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
const sessions = mySqlTable("session", {
|
||||
sessionToken: varchar("sessionToken", { length: 255 })
|
||||
.notNull()
|
||||
.primaryKey(),
|
||||
userId: varchar("userId", { length: 255 })
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: varchar("type", { length: 255 })
|
||||
.$type<AdapterAccount["type"]>()
|
||||
.notNull(),
|
||||
provider: varchar("provider", { length: 255 }).notNull(),
|
||||
providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
|
||||
refresh_token: varchar("refresh_token", { length: 255 }),
|
||||
access_token: varchar("access_token", { length: 255 }),
|
||||
expires_at: int("expires_at"),
|
||||
token_type: varchar("token_type", { length: 255 }),
|
||||
scope: varchar("scope", { length: 255 }),
|
||||
id_token: varchar("id_token", { length: 255 }),
|
||||
session_state: varchar("session_state", { length: 255 }),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
export const sessions = mysqlTable("sessions", {
|
||||
sessionToken: varchar("sessionToken", { length: 255 }).notNull().primaryKey(),
|
||||
userId: varchar("userId", { length: 255 })
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
})
|
||||
|
||||
export const verificationTokens = mysqlTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: varchar("identifier", { length: 255 }).notNull(),
|
||||
token: varchar("token", { length: 255 }).notNull(),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
export type DefaultSchema = typeof schema
|
||||
const verificationTokens = mySqlTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: varchar("identifier", { length: 255 }).notNull(),
|
||||
token: varchar("token", { length: 255 }).notNull(),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
return { users, accounts, sessions, verificationTokens }
|
||||
}
|
||||
|
||||
export type DefaultSchema = ReturnType<typeof createTables>
|
||||
|
||||
export function mySqlDrizzleAdapter(
|
||||
client: MySql2Database<Record<string, never>>
|
||||
client: MySql2Database<Record<string, never>>,
|
||||
tableFn = defaultMySqlTableFn
|
||||
): Adapter {
|
||||
const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(tableFn)
|
||||
|
||||
return {
|
||||
async createUser(data) {
|
||||
const id = crypto.randomUUID()
|
||||
@@ -175,7 +187,7 @@ export function mySqlDrizzleAdapter(
|
||||
return null
|
||||
}
|
||||
|
||||
return dbAccount.users
|
||||
return dbAccount.user
|
||||
},
|
||||
async deleteSession(sessionToken) {
|
||||
const session =
|
||||
|
||||
@@ -1,71 +1,79 @@
|
||||
import { and, eq } from "drizzle-orm"
|
||||
import {
|
||||
timestamp,
|
||||
pgTable,
|
||||
pgTable as defaultPgTableFn,
|
||||
text,
|
||||
primaryKey,
|
||||
integer,
|
||||
PgTableFn,
|
||||
} from "drizzle-orm/pg-core"
|
||||
|
||||
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"
|
||||
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
|
||||
export const users = pgTable("users", {
|
||||
id: text("id").notNull().primaryKey(),
|
||||
name: text("name"),
|
||||
email: text("email").notNull(),
|
||||
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
||||
image: text("image"),
|
||||
})
|
||||
export function createTables(pgTable: PgTableFn) {
|
||||
const users = pgTable("user", {
|
||||
id: text("id").notNull().primaryKey(),
|
||||
name: text("name"),
|
||||
email: text("email").notNull(),
|
||||
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
||||
image: text("image"),
|
||||
})
|
||||
|
||||
export const accounts = pgTable(
|
||||
"accounts",
|
||||
{
|
||||
const accounts = pgTable(
|
||||
"account",
|
||||
{
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
providerAccountId: text("providerAccountId").notNull(),
|
||||
refresh_token: text("refresh_token"),
|
||||
access_token: text("access_token"),
|
||||
expires_at: integer("expires_at"),
|
||||
token_type: text("token_type"),
|
||||
scope: text("scope"),
|
||||
id_token: text("id_token"),
|
||||
session_state: text("session_state"),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
const sessions = pgTable("session", {
|
||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
providerAccountId: text("providerAccountId").notNull(),
|
||||
refresh_token: text("refresh_token"),
|
||||
access_token: text("access_token"),
|
||||
expires_at: integer("expires_at"),
|
||||
token_type: text("token_type"),
|
||||
scope: text("scope"),
|
||||
id_token: text("id_token"),
|
||||
session_state: text("session_state"),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
export const sessions = pgTable("sessions", {
|
||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
})
|
||||
|
||||
export const verificationTokens = pgTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: text("identifier").notNull(),
|
||||
token: text("token").notNull(),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
export type DefaultSchema = typeof schema
|
||||
const verificationTokens = pgTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: text("identifier").notNull(),
|
||||
token: text("token").notNull(),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
return { users, accounts, sessions, verificationTokens }
|
||||
}
|
||||
|
||||
export type DefaultSchema = ReturnType<typeof createTables>
|
||||
|
||||
export function pgDrizzleAdapter(
|
||||
client: PostgresJsDatabase<Record<string, never>>
|
||||
client: PostgresJsDatabase<Record<string, never>>,
|
||||
tableFn = defaultPgTableFn
|
||||
): Adapter {
|
||||
const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(tableFn)
|
||||
|
||||
return {
|
||||
async createUser(data) {
|
||||
return await client
|
||||
@@ -166,7 +174,7 @@ export function pgDrizzleAdapter(
|
||||
return null
|
||||
}
|
||||
|
||||
return dbAccount.users
|
||||
return dbAccount.user
|
||||
},
|
||||
async deleteSession(sessionToken) {
|
||||
const session = await client
|
||||
|
||||
@@ -1,70 +1,78 @@
|
||||
import { eq, and } from "drizzle-orm"
|
||||
import {
|
||||
integer,
|
||||
sqliteTable,
|
||||
sqliteTable as defaultSqliteTableFn,
|
||||
text,
|
||||
primaryKey,
|
||||
BaseSQLiteDatabase,
|
||||
SQLiteTableFn,
|
||||
} from "drizzle-orm/sqlite-core"
|
||||
|
||||
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
|
||||
export const users = sqliteTable("users", {
|
||||
id: text("id").notNull().primaryKey(),
|
||||
name: text("name"),
|
||||
email: text("email").notNull(),
|
||||
emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
|
||||
image: text("image"),
|
||||
})
|
||||
export function createTables(sqliteTable: SQLiteTableFn) {
|
||||
const users = sqliteTable("user", {
|
||||
id: text("id").notNull().primaryKey(),
|
||||
name: text("name"),
|
||||
email: text("email").notNull(),
|
||||
emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
|
||||
image: text("image"),
|
||||
})
|
||||
|
||||
export const accounts = sqliteTable(
|
||||
"accounts",
|
||||
{
|
||||
const accounts = sqliteTable(
|
||||
"account",
|
||||
{
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
providerAccountId: text("providerAccountId").notNull(),
|
||||
refresh_token: text("refresh_token"),
|
||||
access_token: text("access_token"),
|
||||
expires_at: integer("expires_at"),
|
||||
token_type: text("token_type"),
|
||||
scope: text("scope"),
|
||||
id_token: text("id_token"),
|
||||
session_state: text("session_state"),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
const sessions = sqliteTable("session", {
|
||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
providerAccountId: text("providerAccountId").notNull(),
|
||||
refresh_token: text("refresh_token"),
|
||||
access_token: text("access_token"),
|
||||
expires_at: integer("expires_at"),
|
||||
token_type: text("token_type"),
|
||||
scope: text("scope"),
|
||||
id_token: text("id_token"),
|
||||
session_state: text("session_state"),
|
||||
},
|
||||
(account) => ({
|
||||
compoundKey: primaryKey(account.provider, account.providerAccountId),
|
||||
})
|
||||
)
|
||||
|
||||
export const sessions = sqliteTable("sessions", {
|
||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
|
||||
})
|
||||
|
||||
export const verificationTokens = sqliteTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: text("identifier").notNull(),
|
||||
token: text("token").notNull(),
|
||||
expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
export type DefaultSchema = typeof schema
|
||||
const verificationTokens = sqliteTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: text("identifier").notNull(),
|
||||
token: text("token").notNull(),
|
||||
expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
|
||||
},
|
||||
(vt) => ({
|
||||
compoundKey: primaryKey(vt.identifier, vt.token),
|
||||
})
|
||||
)
|
||||
|
||||
return { users, accounts, sessions, verificationTokens }
|
||||
}
|
||||
|
||||
export type DefaultSchema = ReturnType<typeof createTables>
|
||||
|
||||
export function SQLiteDrizzleAdapter(
|
||||
client: BaseSQLiteDatabase<any, any>
|
||||
client: BaseSQLiteDatabase<any, any>,
|
||||
tableFn = defaultSqliteTableFn
|
||||
): Adapter {
|
||||
const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(tableFn)
|
||||
|
||||
return {
|
||||
createUser(data) {
|
||||
return client
|
||||
@@ -151,7 +159,7 @@ export function SQLiteDrizzleAdapter(
|
||||
)
|
||||
.get()
|
||||
|
||||
return results?.users ?? null
|
||||
return results?.user ?? null
|
||||
},
|
||||
deleteSession(sessionToken) {
|
||||
return (
|
||||
|
||||
@@ -2,9 +2,9 @@ import { MySqlDatabase } from "drizzle-orm/mysql-core"
|
||||
import { PgDatabase } from "drizzle-orm/pg-core"
|
||||
import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core"
|
||||
|
||||
import type { AnyMySqlTable } from "drizzle-orm/mysql-core"
|
||||
import type { AnyPgTable } from "drizzle-orm/pg-core"
|
||||
import type { AnySQLiteTable } from "drizzle-orm/sqlite-core"
|
||||
import type { AnyMySqlTable, MySqlTableFn } from "drizzle-orm/mysql-core"
|
||||
import type { AnyPgTable, PgTableFn } from "drizzle-orm/pg-core"
|
||||
import type { AnySQLiteTable, SQLiteTableFn } from "drizzle-orm/sqlite-core"
|
||||
import type { DefaultSchema as PgSchema } from "./pg.js"
|
||||
import type { DefaultSchema as MySqlSchema } from "./mysql.js"
|
||||
import type { DefaultSchema as SQLiteSchema } from "./sqlite.js"
|
||||
@@ -32,6 +32,14 @@ export type ClientFlavors<Flavor> = Flavor extends AnyMySqlDatabase
|
||||
? MinimumSchema["sqlite"]
|
||||
: never
|
||||
|
||||
export type TableFn<Flavor> = Flavor extends AnyMySqlDatabase
|
||||
? MySqlTableFn
|
||||
: Flavor extends AnyPgDatabase
|
||||
? PgTableFn
|
||||
: Flavor extends AnySQLiteDatabase
|
||||
? SQLiteTableFn
|
||||
: AnySQLiteTable
|
||||
|
||||
export function isMySqlDatabase(
|
||||
db: any
|
||||
): db is MySqlDatabase<any, any, any, any> {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { Config } from "drizzle-kit"
|
||||
|
||||
export default {
|
||||
schema: "./tests/mysql/schema.ts",
|
||||
out: "./tests/mysql/.drizzle",
|
||||
driver: "mysql2",
|
||||
dbCredentials: {
|
||||
host: "localhost",
|
||||
user: "root",
|
||||
password: "password",
|
||||
database: "next-auth",
|
||||
},
|
||||
} satisfies Config
|
||||
@@ -0,0 +1,71 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { DrizzleAdapter } from "../../src"
|
||||
import { db, sessions, verificationTokens, accounts, users } from "./schema"
|
||||
import { eq, and } from "drizzle-orm"
|
||||
import { fixtures } from "../fixtures"
|
||||
|
||||
globalThis.crypto ??= require("node:crypto").webcrypto
|
||||
|
||||
runBasicTests({
|
||||
adapter: DrizzleAdapter(db),
|
||||
fixtures,
|
||||
db: {
|
||||
connect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
disconnect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
user: async (id) => {
|
||||
const user = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, id))
|
||||
.then((res) => res[0] ?? null)
|
||||
return user
|
||||
},
|
||||
session: async (sessionToken) => {
|
||||
const session = await db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, sessionToken))
|
||||
.then((res) => res[0] ?? null)
|
||||
|
||||
return session
|
||||
},
|
||||
account: (provider_providerAccountId) => {
|
||||
const account = db
|
||||
.select()
|
||||
.from(accounts)
|
||||
.where(
|
||||
eq(
|
||||
accounts.providerAccountId,
|
||||
provider_providerAccountId.providerAccountId
|
||||
)
|
||||
)
|
||||
.then((res) => res[0] ?? null)
|
||||
return account
|
||||
},
|
||||
verificationToken: (identifier_token) =>
|
||||
db
|
||||
.select()
|
||||
.from(verificationTokens)
|
||||
.where(
|
||||
and(
|
||||
eq(verificationTokens.token, identifier_token.token),
|
||||
eq(verificationTokens.identifier, identifier_token.identifier)
|
||||
)
|
||||
)
|
||||
.then((res) => res[0]) ?? null,
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import { mysqlTableCreator } from "drizzle-orm/mysql-core"
|
||||
import { drizzle } from "drizzle-orm/mysql2"
|
||||
import { createPool } from "mysql2"
|
||||
import { createTables } from "../../src/lib/mysql"
|
||||
|
||||
const poolConnection = createPool({
|
||||
host: "localhost",
|
||||
user: "root",
|
||||
password: "password",
|
||||
database: "next-auth",
|
||||
})
|
||||
|
||||
const mysqlTable = mysqlTableCreator((name) => `foobar_${name}`)
|
||||
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(mysqlTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(poolConnection, { schema })
|
||||
22
packages/adapter-drizzle/tests/mysql-multi-project-schema/test.sh
Executable file
22
packages/adapter-drizzle/tests/mysql-multi-project-schema/test.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Initializing container for MySQL tests."
|
||||
|
||||
MYSQL_DATABASE=next-auth
|
||||
MYSQL_ROOT_PASSWORD=password
|
||||
MYSQL_CONTAINER_NAME=next-auth-mysql-test
|
||||
|
||||
docker run -d --rm \
|
||||
-e MYSQL_DATABASE=${MYSQL_DATABASE} \
|
||||
-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
|
||||
--name "${MYSQL_CONTAINER_NAME}" \
|
||||
-p 3306:3306 \
|
||||
mysql:8 \
|
||||
--default-authentication-plugin=mysql_native_password
|
||||
|
||||
echo "Waiting 15 sec for db to start..." && sleep 15
|
||||
|
||||
drizzle-kit generate:mysql --config=./tests/mysql/drizzle.config.ts
|
||||
drizzle-kit push:mysql --config=./tests/mysql/drizzle.config.ts
|
||||
jest ./tests/mysql/index.test.ts --forceExit
|
||||
docker stop ${MYSQL_CONTAINER_NAME}
|
||||
@@ -1,20 +1,7 @@
|
||||
import type { AdapterAccount } from "@auth/core/adapters"
|
||||
import {
|
||||
mysqlTable,
|
||||
varchar,
|
||||
timestamp,
|
||||
int,
|
||||
primaryKey,
|
||||
} from "drizzle-orm/mysql-core"
|
||||
import { mysqlTable } from "drizzle-orm/mysql-core"
|
||||
import { drizzle } from "drizzle-orm/mysql2"
|
||||
import { createPool } from "mysql2"
|
||||
import {
|
||||
users,
|
||||
accounts,
|
||||
sessions,
|
||||
verificationTokens,
|
||||
schema,
|
||||
} from "../../src/lib/mysql"
|
||||
import { createTables } from "../../src/lib/mysql"
|
||||
|
||||
const poolConnection = createPool({
|
||||
host: "localhost",
|
||||
@@ -23,7 +10,8 @@ const poolConnection = createPool({
|
||||
database: "next-auth",
|
||||
})
|
||||
|
||||
export { users, accounts, sessions, verificationTokens }
|
||||
export const db = drizzle(poolConnection, {
|
||||
schema: schema,
|
||||
})
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(mysqlTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(poolConnection, { schema })
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { Config } from "drizzle-kit"
|
||||
|
||||
export default {
|
||||
schema: "./tests/pg/schema.ts",
|
||||
out: "./tests/pg/.drizzle",
|
||||
dbCredentials: {
|
||||
database: "nextauth",
|
||||
host: "nextauth",
|
||||
user: "nextauth",
|
||||
password: "nextauth",
|
||||
port: 5432,
|
||||
},
|
||||
} satisfies Config
|
||||
@@ -0,0 +1,65 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { DrizzleAdapter } from "../../src"
|
||||
import { db, accounts, sessions, users, verificationTokens } from "./schema"
|
||||
import { eq, and } from "drizzle-orm"
|
||||
import { fixtures } from "../fixtures"
|
||||
|
||||
globalThis.crypto ??= require("node:crypto").webcrypto
|
||||
|
||||
runBasicTests({
|
||||
adapter: DrizzleAdapter(db),
|
||||
fixtures,
|
||||
db: {
|
||||
connect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
disconnect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
user: async (id) =>
|
||||
db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, id))
|
||||
.then((res) => res[0] ?? null),
|
||||
session: (sessionToken) =>
|
||||
db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, sessionToken))
|
||||
.then((res) => res[0] ?? null),
|
||||
account: (provider_providerAccountId) => {
|
||||
return db
|
||||
.select()
|
||||
.from(accounts)
|
||||
.where(
|
||||
eq(
|
||||
accounts.providerAccountId,
|
||||
provider_providerAccountId.providerAccountId
|
||||
)
|
||||
)
|
||||
.then((res) => res[0] ?? null)
|
||||
},
|
||||
verificationToken: (identifier_token) =>
|
||||
db
|
||||
.select()
|
||||
.from(verificationTokens)
|
||||
.where(
|
||||
and(
|
||||
eq(verificationTokens.token, identifier_token.token),
|
||||
eq(verificationTokens.identifier, identifier_token.identifier)
|
||||
)
|
||||
)
|
||||
.then((res) => res[0] ?? null),
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
import { migrate } from "drizzle-orm/postgres-js/migrator"
|
||||
import { db } from "./schema"
|
||||
|
||||
const migrator = async () => {
|
||||
await migrate(db, { migrationsFolder: "./tests/pg/.drizzle" })
|
||||
}
|
||||
|
||||
migrator()
|
||||
.then(() => process.exit(0))
|
||||
.catch(() => process.exit(1))
|
||||
@@ -0,0 +1,17 @@
|
||||
import { drizzle } from "drizzle-orm/postgres-js"
|
||||
import postgres from "postgres"
|
||||
import { createTables } from "../../src/lib/pg"
|
||||
import { pgTableCreator } from "drizzle-orm/pg-core"
|
||||
|
||||
const connectionString = "postgres://nextauth:nextauth@localhost:5432/nextauth"
|
||||
const sql = postgres(connectionString, { max: 1 })
|
||||
|
||||
const pgTable = pgTableCreator((name) => `foobar_${name}`)
|
||||
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(pgTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(sql, {
|
||||
schema,
|
||||
})
|
||||
25
packages/adapter-drizzle/tests/pg-multi-project-schema/test.sh
Executable file
25
packages/adapter-drizzle/tests/pg-multi-project-schema/test.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Initializing container for PostgreSQL tests."
|
||||
|
||||
PGUSER=nextauth
|
||||
PGPASSWORD=nextauth
|
||||
PGDATABASE=nextauth
|
||||
PGPORT=5432
|
||||
PG_CONTAINER_NAME=next-auth-postgres-test
|
||||
|
||||
docker run -d --rm \
|
||||
-e POSTGRES_USER=${PGUSER} \
|
||||
-e POSTGRES_PASSWORD=${PGUSER} \
|
||||
-e POSTGRES_DB=${PGDATABASE} \
|
||||
-e POSTGRES_HOST_AUTH_METHOD=trust \
|
||||
--name "${PG_CONTAINER_NAME}" \
|
||||
-p ${PGPORT}:5432 \
|
||||
postgres:15.3
|
||||
|
||||
echo "Waiting 15 sec for db to start..." && sleep 15
|
||||
|
||||
drizzle-kit generate:pg --config=./tests/pg/drizzle.config.ts
|
||||
npx tsx ./tests/pg/migrator.ts
|
||||
jest ./tests/pg/index.test.ts --forceExit
|
||||
docker stop ${PG_CONTAINER_NAME}
|
||||
@@ -1,11 +1,15 @@
|
||||
import { drizzle } from "drizzle-orm/postgres-js"
|
||||
import postgres from "postgres"
|
||||
import { users, accounts, sessions, verificationTokens } from "../../src/lib/pg"
|
||||
import { createTables } from "../../src/lib/pg"
|
||||
import { pgTable } from "drizzle-orm/pg-core"
|
||||
|
||||
const connectionString = "postgres://nextauth:nextauth@localhost:5432/nextauth"
|
||||
const sql = postgres(connectionString, { max: 1 })
|
||||
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(pgTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(sql, {
|
||||
schema: { users, accounts, sessions, verificationTokens },
|
||||
schema,
|
||||
})
|
||||
export { users, accounts, sessions, verificationTokens }
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { Config } from "drizzle-kit"
|
||||
|
||||
export default {
|
||||
schema: "./tests/sqlite/schema.ts",
|
||||
out: "./tests/sqlite/.drizzle",
|
||||
driver: "better-sqlite",
|
||||
dbCredentials: {
|
||||
url: "./db.sqlite",
|
||||
},
|
||||
} satisfies Config
|
||||
@@ -0,0 +1,60 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { DrizzleAdapter } from "../../src"
|
||||
import { db, accounts, sessions, users, verificationTokens } from "./schema"
|
||||
import { eq, and } from "drizzle-orm"
|
||||
|
||||
globalThis.crypto ??= require("node:crypto").webcrypto
|
||||
|
||||
runBasicTests({
|
||||
adapter: DrizzleAdapter(db),
|
||||
db: {
|
||||
connect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
disconnect: async () => {
|
||||
await Promise.all([
|
||||
db.delete(sessions),
|
||||
db.delete(accounts),
|
||||
db.delete(verificationTokens),
|
||||
db.delete(users),
|
||||
])
|
||||
},
|
||||
user: (id) => db.select().from(users).where(eq(users.id, id)).get() ?? null,
|
||||
session: (sessionToken) =>
|
||||
db
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, sessionToken))
|
||||
.get() ?? null,
|
||||
account: (provider_providerAccountId) => {
|
||||
return (
|
||||
db
|
||||
.select()
|
||||
.from(accounts)
|
||||
.where(
|
||||
eq(
|
||||
accounts.providerAccountId,
|
||||
provider_providerAccountId.providerAccountId
|
||||
)
|
||||
)
|
||||
.get() ?? null
|
||||
)
|
||||
},
|
||||
verificationToken: (identifier_token) =>
|
||||
db
|
||||
.select()
|
||||
.from(verificationTokens)
|
||||
.where(
|
||||
and(
|
||||
eq(verificationTokens.token, identifier_token.token),
|
||||
eq(verificationTokens.identifier, identifier_token.identifier)
|
||||
)
|
||||
)
|
||||
.get() ?? null,
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3"
|
||||
import Database from "better-sqlite3"
|
||||
import { createTables } from "../../src/lib/sqlite"
|
||||
import { sqliteTableCreator } from "drizzle-orm/sqlite-core"
|
||||
|
||||
const sqlite = new Database("db.sqlite")
|
||||
|
||||
const sqliteTable = sqliteTableCreator((name) => `foobar_${name}`)
|
||||
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(sqliteTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(sqlite, { schema })
|
||||
12
packages/adapter-drizzle/tests/sqlite-multi-project-schema/test.sh
Executable file
12
packages/adapter-drizzle/tests/sqlite-multi-project-schema/test.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
|
||||
echo "Running SQLite tests."
|
||||
|
||||
rm -f db.sqlite
|
||||
|
||||
drizzle-kit generate:sqlite --config=./tests/sqlite/drizzle.config.ts
|
||||
drizzle-kit push:sqlite --config=./tests/sqlite/drizzle.config.ts
|
||||
jest ./tests/sqlite/index.test.ts --forceExit
|
||||
@@ -1,20 +1,12 @@
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3"
|
||||
import Database from "better-sqlite3"
|
||||
import {
|
||||
users,
|
||||
accounts,
|
||||
sessions,
|
||||
verificationTokens,
|
||||
} from "../../src/lib/sqlite"
|
||||
import { createTables } from "../../src/lib/sqlite"
|
||||
import { sqliteTable } from "drizzle-orm/sqlite-core"
|
||||
|
||||
const sqlite = new Database("db.sqlite")
|
||||
|
||||
export { users, accounts, sessions, verificationTokens }
|
||||
export const db = drizzle(sqlite, {
|
||||
schema: {
|
||||
users,
|
||||
accounts,
|
||||
sessions,
|
||||
verificationTokens,
|
||||
},
|
||||
})
|
||||
export const { users, accounts, sessions, verificationTokens } =
|
||||
createTables(sqliteTable)
|
||||
export const schema = { users, accounts, sessions, verificationTokens }
|
||||
|
||||
export const db = drizzle(sqlite, { schema })
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
28
packages/adapter-kysely/README.md
Normal file
28
packages/adapter-kysely/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
<p align="center">
|
||||
<br/>
|
||||
<a href="https://authjs.dev" target="_blank">
|
||||
<img height="64px" src="https://authjs.dev/img/logo/logo-sm.png" />
|
||||
</a>
|
||||
<a href="https://kysely.io" target="_blank">
|
||||
<img height="64px" src="https://authjs.dev/img/adapters/kysely.svg"/>
|
||||
</a>
|
||||
<h3 align="center"><b>Kysely Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@auth/kysely-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@auth/kysely-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/kysely-adapter?color=green&label=@auth/kysely-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@auth/kysely-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/kysely-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
Check out the documentation at [authjs.dev](https://authjs.dev/reference/adapter/kysely).
|
||||
56
packages/adapter-kysely/package.json
Normal file
56
packages/adapter-kysely/package.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "@auth/kysely-adapter",
|
||||
"version": "0.1.1",
|
||||
"description": "Kysely adapter for Auth.js",
|
||||
"homepage": "https://authjs.dev/reference/adapter/kysely",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "mwojtul <mark.wojtul@gmail.com> (https://github.com/mwojtul)",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"authjs",
|
||||
"next-auth",
|
||||
"next.js",
|
||||
"oauth",
|
||||
"kysely"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "./tests/test.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"kysely": "^0.26.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@types/better-sqlite3": "^7.6.3",
|
||||
"@types/pg": "^8.6.5",
|
||||
"better-sqlite3": "^8.2.0",
|
||||
"jest": "^27.4.3",
|
||||
"kysely": "^0.24.2",
|
||||
"mysql2": "^3.2.0",
|
||||
"pg": "^8.10.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
472
packages/adapter-kysely/src/index.ts
Normal file
472
packages/adapter-kysely/src/index.ts
Normal file
@@ -0,0 +1,472 @@
|
||||
/**
|
||||
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
|
||||
* <p style={{fontWeight: "normal"}}>Official <a href="https://kysely.dev/">Kysely</a> adapter for Auth.js / NextAuth.js.</p>
|
||||
* <a href="https://kysely.dev/">
|
||||
* <img style={{display: "block"}} src="/img/adapters/kysely.svg" width="38" />
|
||||
* </a>
|
||||
* </div>
|
||||
*
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install kysely @auth/kysely-adapter
|
||||
* ```
|
||||
*
|
||||
* @module @auth/kysely-adapter
|
||||
*/
|
||||
|
||||
import { Kysely, SqliteAdapter } from "kysely"
|
||||
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
import type { GeneratedAlways } from "kysely"
|
||||
|
||||
export interface Database {
|
||||
User: {
|
||||
id: GeneratedAlways<string>
|
||||
name: string | null
|
||||
email: string
|
||||
emailVerified: Date | string | null
|
||||
image: string | null
|
||||
}
|
||||
Account: {
|
||||
id: GeneratedAlways<string>
|
||||
userId: string
|
||||
type: string
|
||||
provider: string
|
||||
providerAccountId: string
|
||||
refresh_token: string | null
|
||||
access_token: string | null
|
||||
expires_at: number | null
|
||||
token_type: string | null
|
||||
scope: string | null
|
||||
id_token: string | null
|
||||
session_state: string | null
|
||||
}
|
||||
Session: {
|
||||
id: GeneratedAlways<string>
|
||||
userId: string
|
||||
sessionToken: string
|
||||
expires: Date | string
|
||||
}
|
||||
VerificationToken: {
|
||||
identifier: string
|
||||
token: string
|
||||
expires: Date | string
|
||||
}
|
||||
}
|
||||
|
||||
export const format = {
|
||||
/**
|
||||
* Helper function to return the passed in object and its specified prop
|
||||
* as an ISO string if SQLite is being used.
|
||||
*/
|
||||
from<T extends Partial<Record<K, Date | null>>, K extends keyof T>(
|
||||
data: T,
|
||||
key: K,
|
||||
isSqlite: boolean
|
||||
) {
|
||||
const value = data[key]
|
||||
return {
|
||||
...data,
|
||||
[key]: value && isSqlite ? value.toISOString() : value,
|
||||
}
|
||||
},
|
||||
to,
|
||||
}
|
||||
|
||||
type ReturnData<T = never> = Record<string, Date | string | T>
|
||||
|
||||
/**
|
||||
* Helper function to return the passed in object and its specified prop as a date.
|
||||
* Necessary because SQLite has no date type so we store dates as ISO strings.
|
||||
*/
|
||||
function to<T extends Partial<ReturnData>, K extends keyof T>(
|
||||
data: T,
|
||||
key: K
|
||||
): Omit<T, K> & Record<K, Date>
|
||||
function to<T extends Partial<ReturnData<null>>, K extends keyof T>(
|
||||
data: T,
|
||||
key: K
|
||||
): Omit<T, K> & Record<K, Date | null>
|
||||
function to<T extends Partial<ReturnData<null>>, K extends keyof T>(
|
||||
data: T,
|
||||
key: K
|
||||
) {
|
||||
const value = data[key]
|
||||
return Object.assign(data, {
|
||||
[key]: value && typeof value === "string" ? new Date(value) : value,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* ## Setup
|
||||
*
|
||||
* This adapter supports the same first party dialects that Kysely (as of v0.24.2) supports: PostgreSQL, MySQL, and SQLite. The examples below use PostgreSQL with the [pg](https://www.npmjs.com/package/pg) client.
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install pg
|
||||
* npm install --save-dev @types/pg
|
||||
* ```
|
||||
*
|
||||
* ```typescript title="pages/api/auth/[...nextauth].ts"
|
||||
* import NextAuth from "next-auth"
|
||||
* import GoogleProvider from "next-auth/providers/google"
|
||||
* import { KyselyAdapter } from "@auth/kysely-adapter"
|
||||
* import { db } from "../../../db"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: KyselyAdapter(db),
|
||||
* providers: [
|
||||
* GoogleProvider({
|
||||
* clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
* clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
* }),
|
||||
* ],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* Kysely's constructor requires a database interface that contains an entry with an interface for each of your tables. You can define these types manually, or use `kysely-codegen` / `prisma-kysely` to automatically generate them. Check out the default [models](/reference/adapters#models) required by Auth.js.
|
||||
*
|
||||
* ```ts title="db.ts"
|
||||
* import { PostgresDialect } from "kysely"
|
||||
* import { Pool } from "pg"
|
||||
*
|
||||
* // This adapter exports a wrapper of the original `Kysely` class called `KyselyAuth`,
|
||||
* // that can be used to provide additional type-safety.
|
||||
* // While using it isn't required, it is recommended as it will verify
|
||||
* // that the database interface has all the fields that Auth.js expects.
|
||||
* import { KyselyAuth } from "@auth/kysely-adapter"
|
||||
*
|
||||
* import type { GeneratedAlways } from "kysely"
|
||||
*
|
||||
* interface Database {
|
||||
* User: {
|
||||
* id: GeneratedAlways<string>
|
||||
* name: string | null
|
||||
* email: string
|
||||
* emailVerified: Date | null
|
||||
* image: string | null
|
||||
* }
|
||||
* Account: {
|
||||
* id: GeneratedAlways<string>
|
||||
* userId: string
|
||||
* type: string
|
||||
* provider: string
|
||||
* providerAccountId: string
|
||||
* refresh_token: string | null
|
||||
* access_token: string | null
|
||||
* expires_at: number | null
|
||||
* token_type: string | null
|
||||
* scope: string | null
|
||||
* id_token: string | null
|
||||
* session_state: string | null
|
||||
* }
|
||||
* Session: {
|
||||
* id: GeneratedAlways<string>
|
||||
* userId: string
|
||||
* sessionToken: string
|
||||
* expires: Date
|
||||
* }
|
||||
* VerificationToken: {
|
||||
* identifier: string
|
||||
* token: string
|
||||
* expires: Date
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* export const db = new KyselyAuth<Database>({
|
||||
* dialect: new PostgresDialect({
|
||||
* pool: new Pool({
|
||||
* host: process.env.DATABASE_HOST,
|
||||
* database: process.env.DATABASE_NAME,
|
||||
* user: process.env.DATABASE_USER,
|
||||
* password: process.env.DATABASE_PASSWORD,
|
||||
* }),
|
||||
* }),
|
||||
* })
|
||||
```
|
||||
*
|
||||
*
|
||||
* :::note
|
||||
* An alternative to manually defining types is generating them from the database schema using [kysely-codegen](https://github.com/RobinBlomberg/kysely-codegen), or from Prisma schemas using [prisma-kysely](https://github.com/valtyr/prisma-kysely). When using generated types with `KyselyAuth`, import `Codegen` and pass it as the second generic arg:
|
||||
* ```ts
|
||||
* import type { Codegen } from "@auth/kysely-adapter"
|
||||
* new KyselyAuth<Database, Codegen>(...)
|
||||
* ```
|
||||
* :::
|
||||
* ### Schema
|
||||
* ```ts title="db/migrations/001_create_db.ts"
|
||||
* import { Kysely, sql } from "kysely"
|
||||
*
|
||||
* export async function up(db: Kysely<any>): Promise<void> {
|
||||
* await db.schema
|
||||
* .createTable("User")
|
||||
* .addColumn("id", "uuid", (col) =>
|
||||
* col.primaryKey().defaultTo(sql`gen_random_uuid()`)
|
||||
* )
|
||||
* .addColumn("name", "text")
|
||||
* .addColumn("email", "text", (col) => col.unique().notNull())
|
||||
* .addColumn("emailVerified", "timestamptz")
|
||||
* .addColumn("image", "text")
|
||||
* .execute()
|
||||
*
|
||||
* await db.schema
|
||||
* .createTable("Account")
|
||||
* .addColumn("id", "uuid", (col) =>
|
||||
* col.primaryKey().defaultTo(sql`gen_random_uuid()`)
|
||||
* )
|
||||
* .addColumn("userId", "uuid", (col) =>
|
||||
* col.references("User.id").onDelete("cascade").notNull()
|
||||
* )
|
||||
* .addColumn("type", "text", (col) => col.notNull())
|
||||
* .addColumn("provider", "text", (col) => col.notNull())
|
||||
* .addColumn("providerAccountId", "text", (col) => col.notNull())
|
||||
* .addColumn("refresh_token", "text")
|
||||
* .addColumn("access_token", "text")
|
||||
* .addColumn("expires_at", "bigint")
|
||||
* .addColumn("token_type", "text")
|
||||
* .addColumn("scope", "text")
|
||||
* .addColumn("id_token", "text")
|
||||
* .addColumn("session_state", "text")
|
||||
* .execute()
|
||||
*
|
||||
* await db.schema
|
||||
* .createTable("Session")
|
||||
* .addColumn("id", "uuid", (col) =>
|
||||
* col.primaryKey().defaultTo(sql`gen_random_uuid()`)
|
||||
* )
|
||||
* .addColumn("userId", "uuid", (col) =>
|
||||
* col.references("User.id").onDelete("cascade").notNull()
|
||||
* )
|
||||
* .addColumn("sessionToken", "text", (col) => col.notNull().unique())
|
||||
* .addColumn("expires", "timestamptz", (col) => col.notNull())
|
||||
* .execute()
|
||||
*
|
||||
* await db.schema
|
||||
* .createTable("VerificationToken")
|
||||
* .addColumn("identifier", "text", (col) => col.notNull())
|
||||
* .addColumn("token", "text", (col) => col.notNull().unique())
|
||||
* .addColumn("expires", "timestamptz", (col) => col.notNull())
|
||||
* .execute()
|
||||
*
|
||||
* await db.schema
|
||||
* .createIndex("Account_userId_index")
|
||||
* .on("Account")
|
||||
* .column("userId")
|
||||
* .execute()
|
||||
*
|
||||
* await db.schema
|
||||
* .createIndex("Session_userId_index")
|
||||
* .on("Session")
|
||||
* .column("userId")
|
||||
* .execute()
|
||||
* }
|
||||
*
|
||||
* export async function down(db: Kysely<any>): Promise<void> {
|
||||
* await db.schema.dropTable("Account").ifExists().execute()
|
||||
* await db.schema.dropTable("Session").ifExists().execute()
|
||||
* await db.schema.dropTable("User").ifExists().execute()
|
||||
* await db.schema.dropTable("VerificationToken").ifExists().execute()
|
||||
* }
|
||||
* ```
|
||||
* > This schema is adapted for use in Kysely and is based upon our main [schema](/reference/adapters#models).
|
||||
*
|
||||
* For more information about creating and running migrations with Kysely, refer to the [Kysely migrations documentation](https://kysely.dev/docs/migrations).
|
||||
*
|
||||
* ### Naming conventions
|
||||
* If mixed snake_case and camelCase column names is an issue for you and/or your underlying database system, we recommend using Kysely's `CamelCasePlugin` ([see the documentation here](https://kysely-org.github.io/kysely/classes/CamelCasePlugin.html)) feature to change the field names. This won't affect NextAuth.js, but will allow you to have consistent casing when using Kysely.
|
||||
*/
|
||||
export function KyselyAdapter(db: Kysely<Database>): Adapter {
|
||||
const { adapter } = db.getExecutor()
|
||||
const supportsReturning = adapter.supportsReturning
|
||||
const isSqlite = adapter instanceof SqliteAdapter
|
||||
|
||||
return {
|
||||
async createUser(data) {
|
||||
const userData = format.from(data, "emailVerified", isSqlite)
|
||||
const query = db.insertInto("User").values(userData)
|
||||
const result = supportsReturning
|
||||
? await query.returningAll().executeTakeFirstOrThrow()
|
||||
: await query.executeTakeFirstOrThrow().then(async () => {
|
||||
return await db
|
||||
.selectFrom("User")
|
||||
.selectAll()
|
||||
.where("email", "=", `${userData.email}`)
|
||||
.executeTakeFirstOrThrow()
|
||||
})
|
||||
return to(result, "emailVerified")
|
||||
},
|
||||
async getUser(id) {
|
||||
const result =
|
||||
(await db
|
||||
.selectFrom("User")
|
||||
.selectAll()
|
||||
.where("id", "=", id)
|
||||
.executeTakeFirst()) ?? null
|
||||
if (!result) return null
|
||||
return to(result, "emailVerified")
|
||||
},
|
||||
async getUserByEmail(email) {
|
||||
const result =
|
||||
(await db
|
||||
.selectFrom("User")
|
||||
.selectAll()
|
||||
.where("email", "=", email)
|
||||
.executeTakeFirst()) ?? null
|
||||
if (!result) return null
|
||||
return to(result, "emailVerified")
|
||||
},
|
||||
async getUserByAccount({ providerAccountId, provider }) {
|
||||
const result =
|
||||
(await db
|
||||
.selectFrom("User")
|
||||
.innerJoin("Account", "User.id", "Account.userId")
|
||||
.selectAll("User")
|
||||
.where("Account.providerAccountId", "=", providerAccountId)
|
||||
.where("Account.provider", "=", provider)
|
||||
.executeTakeFirst()) ?? null
|
||||
if (!result) return null
|
||||
return to(result, "emailVerified")
|
||||
},
|
||||
async updateUser({ id, ...user }) {
|
||||
if (!id) throw new Error("User not found")
|
||||
const userData = format.from(user, "emailVerified", isSqlite)
|
||||
const query = db.updateTable("User").set(userData).where("id", "=", id)
|
||||
const result = supportsReturning
|
||||
? await query.returningAll().executeTakeFirstOrThrow()
|
||||
: await query.executeTakeFirstOrThrow().then(async () => {
|
||||
return await db
|
||||
.selectFrom("User")
|
||||
.selectAll()
|
||||
.where("id", "=", id)
|
||||
.executeTakeFirstOrThrow()
|
||||
})
|
||||
return to(result, "emailVerified")
|
||||
},
|
||||
async deleteUser(userId) {
|
||||
await db.deleteFrom("User").where("User.id", "=", userId).execute()
|
||||
},
|
||||
async linkAccount(account) {
|
||||
await db.insertInto("Account").values(account).executeTakeFirstOrThrow()
|
||||
},
|
||||
async unlinkAccount({ providerAccountId, provider }) {
|
||||
await db
|
||||
.deleteFrom("Account")
|
||||
.where("Account.providerAccountId", "=", providerAccountId)
|
||||
.where("Account.provider", "=", provider)
|
||||
.executeTakeFirstOrThrow()
|
||||
},
|
||||
async createSession(data) {
|
||||
const sessionData = format.from(data, "expires", isSqlite)
|
||||
const query = db.insertInto("Session").values(sessionData)
|
||||
const result = supportsReturning
|
||||
? await query.returningAll().executeTakeFirstOrThrow()
|
||||
: await (async () => {
|
||||
await query.executeTakeFirstOrThrow()
|
||||
return await db
|
||||
.selectFrom("Session")
|
||||
.selectAll()
|
||||
.where("sessionToken", "=", sessionData.sessionToken)
|
||||
.executeTakeFirstOrThrow()
|
||||
})()
|
||||
return to(result, "expires")
|
||||
},
|
||||
async getSessionAndUser(sessionTokenArg) {
|
||||
const result = await db
|
||||
.selectFrom("Session")
|
||||
.innerJoin("User", "User.id", "Session.userId")
|
||||
.selectAll("User")
|
||||
.select([
|
||||
"Session.id as sessionId",
|
||||
"Session.userId",
|
||||
"Session.sessionToken",
|
||||
"Session.expires",
|
||||
])
|
||||
.where("Session.sessionToken", "=", sessionTokenArg)
|
||||
.executeTakeFirst()
|
||||
if (!result) return null
|
||||
const { sessionId: id, userId, sessionToken, expires, ...user } = result
|
||||
return {
|
||||
user: to({ ...user }, "emailVerified"),
|
||||
session: to({ id, userId, sessionToken, expires }, "expires"),
|
||||
}
|
||||
},
|
||||
async updateSession(session) {
|
||||
const sessionData = format.from(session, "expires", isSqlite)
|
||||
const query = db
|
||||
.updateTable("Session")
|
||||
.set(sessionData)
|
||||
.where("Session.sessionToken", "=", session.sessionToken)
|
||||
const result = supportsReturning
|
||||
? await query.returningAll().executeTakeFirstOrThrow()
|
||||
: await query.executeTakeFirstOrThrow().then(async () => {
|
||||
return await db
|
||||
.selectFrom("Session")
|
||||
.selectAll()
|
||||
.where("Session.sessionToken", "=", sessionData.sessionToken)
|
||||
.executeTakeFirstOrThrow()
|
||||
})
|
||||
return to(result, "expires")
|
||||
},
|
||||
async deleteSession(sessionToken) {
|
||||
await db
|
||||
.deleteFrom("Session")
|
||||
.where("Session.sessionToken", "=", sessionToken)
|
||||
.executeTakeFirstOrThrow()
|
||||
},
|
||||
async createVerificationToken(verificationToken) {
|
||||
const verificationTokenData = format.from(
|
||||
verificationToken,
|
||||
"expires",
|
||||
isSqlite
|
||||
)
|
||||
const query = db
|
||||
.insertInto("VerificationToken")
|
||||
.values(verificationTokenData)
|
||||
const result = supportsReturning
|
||||
? await query.returningAll().executeTakeFirstOrThrow()
|
||||
: await query.executeTakeFirstOrThrow().then(async () => {
|
||||
return await db
|
||||
.selectFrom("VerificationToken")
|
||||
.selectAll()
|
||||
.where("token", "=", verificationTokenData.token)
|
||||
.executeTakeFirstOrThrow()
|
||||
})
|
||||
return to(result, "expires")
|
||||
},
|
||||
async useVerificationToken({ identifier, token }) {
|
||||
const query = db
|
||||
.deleteFrom("VerificationToken")
|
||||
.where("VerificationToken.token", "=", token)
|
||||
.where("VerificationToken.identifier", "=", identifier)
|
||||
const result = supportsReturning
|
||||
? (await query.returningAll().executeTakeFirst()) ?? null
|
||||
: await db
|
||||
.selectFrom("VerificationToken")
|
||||
.selectAll()
|
||||
.where("token", "=", token)
|
||||
.executeTakeFirst()
|
||||
.then(async (res) => {
|
||||
await query.executeTakeFirst()
|
||||
return res
|
||||
})
|
||||
if (!result) return null
|
||||
return to(result, "expires")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper over the original `Kysely` class in order to validate the passed in
|
||||
* database interface. A regular Kysely instance may also be used, but wrapping
|
||||
* it ensures the database interface implements the fields that Auth.js
|
||||
* requires. When used with `kysely-codegen`, the `Codegen` type can be passed as
|
||||
* the second generic argument. The generated types will be used, and
|
||||
* `KyselyAuth` will only verify that the correct fields exist.
|
||||
**/
|
||||
export class KyselyAuth<DB extends T, T = Database> extends Kysely<DB> {}
|
||||
|
||||
export type Codegen = {
|
||||
[K in keyof Database]: { [J in keyof Database[K]]: unknown }
|
||||
}
|
||||
250
packages/adapter-kysely/tests/index.test.ts
Normal file
250
packages/adapter-kysely/tests/index.test.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { Pool } from "pg"
|
||||
import {
|
||||
Kysely,
|
||||
MysqlDialect,
|
||||
PostgresDialect,
|
||||
SchemaModule,
|
||||
sql,
|
||||
SqliteAdapter,
|
||||
SqliteDialect,
|
||||
} from "kysely"
|
||||
import { KyselyAdapter, KyselyAuth } from "../src"
|
||||
import { createPool } from "mysql2"
|
||||
import SqliteDatabase from "better-sqlite3"
|
||||
import type { Database } from "../src"
|
||||
import { DataTypeExpression } from "kysely/dist/cjs/parser/data-type-parser"
|
||||
|
||||
type BuiltInDialect = "postgres" | "mysql" | "sqlite"
|
||||
|
||||
const POOL_SIZE = 20
|
||||
const DIALECT_CONFIGS = {
|
||||
postgres: {
|
||||
host: "localhost",
|
||||
database: "kysely_test",
|
||||
user: "kysely",
|
||||
port: 5434,
|
||||
max: POOL_SIZE,
|
||||
},
|
||||
mysql: {
|
||||
database: "kysely_test",
|
||||
host: "localhost",
|
||||
user: "kysely",
|
||||
password: "kysely",
|
||||
port: 3308,
|
||||
supportBigNumbers: true,
|
||||
bigNumberStrings: true,
|
||||
connectionLimit: POOL_SIZE,
|
||||
},
|
||||
sqlite: {
|
||||
databasePath: ":memory:",
|
||||
},
|
||||
} as const
|
||||
|
||||
async function dropDatabase(db: Kysely<Database>): Promise<void> {
|
||||
await Promise.all([
|
||||
db.schema.dropTable("Account").ifExists().execute(),
|
||||
db.schema.dropTable("Session").ifExists().execute(),
|
||||
db.schema.dropTable("User").ifExists().execute(),
|
||||
db.schema.dropTable("VerificationToken").ifExists().execute(),
|
||||
])
|
||||
}
|
||||
|
||||
export function createTableWithId(
|
||||
schema: SchemaModule,
|
||||
dialect: BuiltInDialect,
|
||||
tableName: string
|
||||
) {
|
||||
const builder = schema.createTable(tableName)
|
||||
|
||||
if (dialect === "postgres") {
|
||||
return builder.addColumn("id", "uuid", (col) =>
|
||||
col.primaryKey().defaultTo(sql`gen_random_uuid()`)
|
||||
)
|
||||
} else if (dialect === "mysql") {
|
||||
return builder.addColumn("id", "varchar(36)", (col) =>
|
||||
col.primaryKey().defaultTo(sql`(UUID())`)
|
||||
)
|
||||
} else {
|
||||
return builder.addColumn("id", "integer", (col) =>
|
||||
col.autoIncrement().primaryKey()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function createDatabase(
|
||||
db: Kysely<Database>,
|
||||
dialect: BuiltInDialect
|
||||
): Promise<void> {
|
||||
const defaultTimestamp = {
|
||||
postgres: sql`NOW()`,
|
||||
mysql: sql`NOW(3)`,
|
||||
sqlite: sql`CURRENT_TIMESTAMP`,
|
||||
}[dialect]
|
||||
const uuidColumnType: DataTypeExpression =
|
||||
dialect === "mysql" ? "varchar(36)" : "uuid"
|
||||
const dateColumnType: DataTypeExpression =
|
||||
dialect === "mysql" ? sql`DATETIME(3)` : "timestamptz"
|
||||
const textColumnType: DataTypeExpression =
|
||||
dialect === "mysql" ? "varchar(255)" : "text"
|
||||
|
||||
await dropDatabase(db)
|
||||
|
||||
await createTableWithId(db.schema, dialect, "User")
|
||||
.addColumn("name", textColumnType)
|
||||
.addColumn("email", textColumnType, (col) => col.unique().notNull())
|
||||
.addColumn("emailVerified", dateColumnType, (col) =>
|
||||
col.defaultTo(defaultTimestamp)
|
||||
)
|
||||
.addColumn("image", textColumnType)
|
||||
.execute()
|
||||
|
||||
let createAccountTable = createTableWithId(db.schema, dialect, "Account")
|
||||
.addColumn("userId", uuidColumnType, (col) =>
|
||||
col.references("User.id").onDelete("cascade").notNull()
|
||||
)
|
||||
.addColumn("type", textColumnType, (col) => col.notNull())
|
||||
.addColumn("provider", textColumnType, (col) => col.notNull())
|
||||
.addColumn("providerAccountId", textColumnType, (col) => col.notNull())
|
||||
.addColumn("refresh_token", textColumnType)
|
||||
.addColumn("access_token", textColumnType)
|
||||
.addColumn("expires_at", "bigint")
|
||||
.addColumn("token_type", textColumnType)
|
||||
.addColumn("scope", textColumnType)
|
||||
.addColumn("id_token", textColumnType)
|
||||
.addColumn("session_state", textColumnType)
|
||||
if (dialect === "mysql")
|
||||
createAccountTable = createAccountTable.addForeignKeyConstraint(
|
||||
"Account_userId_fk",
|
||||
["userId"],
|
||||
"User",
|
||||
["id"],
|
||||
(cb) => cb.onDelete("cascade")
|
||||
)
|
||||
await createAccountTable.execute()
|
||||
|
||||
let createSessionTable = createTableWithId(db.schema, dialect, "Session")
|
||||
.addColumn("userId", uuidColumnType, (col) =>
|
||||
col.references("User.id").onDelete("cascade").notNull()
|
||||
)
|
||||
.addColumn("sessionToken", textColumnType, (col) => col.notNull().unique())
|
||||
.addColumn("expires", dateColumnType, (col) => col.notNull())
|
||||
|
||||
if (dialect === "mysql")
|
||||
createSessionTable = createSessionTable.addForeignKeyConstraint(
|
||||
"Session_userId_fk",
|
||||
["userId"],
|
||||
"User",
|
||||
["id"],
|
||||
(cb) => cb.onDelete("cascade")
|
||||
)
|
||||
await createSessionTable.execute()
|
||||
|
||||
await db.schema
|
||||
.createTable("VerificationToken")
|
||||
.addColumn("identifier", textColumnType, (col) => col.notNull())
|
||||
.addColumn("token", textColumnType, (col) => col.notNull().unique())
|
||||
.addColumn("expires", dateColumnType, (col) => col.notNull())
|
||||
.execute()
|
||||
|
||||
await db.schema
|
||||
.createIndex("Account_userId_index")
|
||||
.on("Account")
|
||||
.column("userId")
|
||||
.execute()
|
||||
}
|
||||
|
||||
const runDialectBasicTests = (
|
||||
db: Kysely<Database>,
|
||||
dialect: BuiltInDialect
|
||||
) => {
|
||||
const datesStoredAsISOStrings =
|
||||
db.getExecutor().adapter instanceof SqliteAdapter
|
||||
|
||||
runBasicTests({
|
||||
adapter: KyselyAdapter(db),
|
||||
db: {
|
||||
async connect() {
|
||||
await dropDatabase(db)
|
||||
await createDatabase(db, dialect)
|
||||
},
|
||||
async disconnect() {
|
||||
await db.destroy()
|
||||
},
|
||||
async user(userId) {
|
||||
const user =
|
||||
(await db
|
||||
.selectFrom("User")
|
||||
.selectAll()
|
||||
.where("id", "=", userId)
|
||||
.executeTakeFirst()) ?? null
|
||||
if (datesStoredAsISOStrings && user?.emailVerified)
|
||||
user.emailVerified = new Date(user.emailVerified)
|
||||
return user
|
||||
},
|
||||
async account({ provider, providerAccountId }) {
|
||||
const result = await db
|
||||
.selectFrom("Account")
|
||||
.selectAll()
|
||||
.where("provider", "=", provider)
|
||||
.where("providerAccountId", "=", providerAccountId)
|
||||
.executeTakeFirst()
|
||||
if (!result) return null
|
||||
const { ...account } = result
|
||||
if (typeof account.expires_at === "string")
|
||||
account.expires_at = Number(account.expires_at)
|
||||
return account
|
||||
},
|
||||
async session(sessionToken) {
|
||||
const session =
|
||||
(await db
|
||||
.selectFrom("Session")
|
||||
.selectAll()
|
||||
.where("sessionToken", "=", sessionToken)
|
||||
.executeTakeFirst()) ?? null
|
||||
if (datesStoredAsISOStrings && session?.expires)
|
||||
session.expires = new Date(session.expires)
|
||||
return session
|
||||
},
|
||||
async verificationToken({ identifier, token }) {
|
||||
const verificationToken = await db
|
||||
.selectFrom("VerificationToken")
|
||||
.selectAll()
|
||||
.where("identifier", "=", identifier)
|
||||
.where("token", "=", token)
|
||||
.executeTakeFirstOrThrow()
|
||||
if (datesStoredAsISOStrings)
|
||||
verificationToken.expires = new Date(verificationToken.expires)
|
||||
return verificationToken
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
describe("Testing PostgresDialect", () => {
|
||||
const db = new KyselyAuth<Database>({
|
||||
dialect: new PostgresDialect({
|
||||
pool: new Pool(DIALECT_CONFIGS.postgres),
|
||||
}),
|
||||
})
|
||||
runDialectBasicTests(db, "postgres")
|
||||
})
|
||||
|
||||
describe("Testing MysqlDialect", () => {
|
||||
const db = new KyselyAuth<Database>({
|
||||
dialect: new MysqlDialect({
|
||||
pool: createPool(DIALECT_CONFIGS.mysql),
|
||||
}),
|
||||
})
|
||||
runDialectBasicTests(db, "mysql")
|
||||
})
|
||||
|
||||
describe("Testing SqliteDialect", () => {
|
||||
const db = new KyselyAuth<Database>({
|
||||
dialect: new SqliteDialect({
|
||||
database: async () =>
|
||||
new SqliteDatabase(DIALECT_CONFIGS.sqlite.databasePath),
|
||||
}),
|
||||
})
|
||||
runDialectBasicTests(db, "sqlite")
|
||||
})
|
||||
3
packages/adapter-kysely/tests/scripts/mysql-init.sql
Normal file
3
packages/adapter-kysely/tests/scripts/mysql-init.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
CREATE USER 'kysely'@'%' IDENTIFIED WITH mysql_native_password BY 'kysely';
|
||||
GRANT ALL ON *.* TO 'kysely'@'%';
|
||||
CREATE DATABASE kysely_test;
|
||||
30
packages/adapter-kysely/tests/test.sh
Executable file
30
packages/adapter-kysely/tests/test.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
docker run -d \
|
||||
--name mysql \
|
||||
--rm \
|
||||
-e MYSQL_ROOT_PASSWORD=root \
|
||||
-e MYSQL_DATABASE=kysely_test \
|
||||
-p 3308:3306 \
|
||||
-v "$(pwd)"/tests/scripts/mysql-init.sql:/data/application/init.sql \
|
||||
mysql/mysql-server \
|
||||
--init-file /data/application/init.sql
|
||||
|
||||
docker run -d \
|
||||
--name postgres \
|
||||
--rm \
|
||||
-e POSTGRES_DB=kysely_test \
|
||||
-e POSTGRES_USER=kysely \
|
||||
-e POSTGRES_HOST_AUTH_METHOD=trust \
|
||||
-p 5434:5432 \
|
||||
postgres
|
||||
|
||||
echo "waiting 15 seconds for databases to start..."
|
||||
sleep 15
|
||||
|
||||
# Always stop container, but exit with 1 when tests are failing
|
||||
if npx jest tests; then
|
||||
docker stop mysql && docker stop postgres
|
||||
else
|
||||
docker stop mysql && docker stop postgres && exit 1
|
||||
fi
|
||||
25
packages/adapter-kysely/tsconfig.json
Normal file
25
packages/adapter-kysely/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/core",
|
||||
"version": "0.10.1",
|
||||
"version": "0.11.0",
|
||||
"description": "Authentication for the Web.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
|
||||
@@ -270,3 +270,18 @@ export interface Adapter {
|
||||
token: string
|
||||
}): Awaitable<VerificationToken | null>
|
||||
}
|
||||
|
||||
// For compatibility with older versions of NextAuth.js
|
||||
// @ts-expect-error
|
||||
declare module "next-auth/adapters" {
|
||||
type JsonObject = {
|
||||
[Key in string]?: JsonValue
|
||||
}
|
||||
type JsonArray = JsonValue[]
|
||||
type JsonPrimitive = string | number | boolean | null
|
||||
type JsonValue = JsonPrimitive | JsonObject | JsonArray
|
||||
interface AdapterAccount {
|
||||
type: "oauth" | "email" | "oidc"
|
||||
[key: string]: JsonValue | undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,8 +162,8 @@ export class SessionStore {
|
||||
get value() {
|
||||
// Sort the chunks by their keys before joining
|
||||
const sortedKeys = Object.keys(this.#chunks).sort((a, b) => {
|
||||
const aSuffix = parseInt(a.split(".")[1] || "0");
|
||||
const bSuffix = parseInt(b.split(".")[1] || "0");
|
||||
const aSuffix = parseInt(a.split(".").pop() || "0");
|
||||
const bSuffix = parseInt(b.split(".").pop() || "0");
|
||||
|
||||
return aSuffix - bSuffix;
|
||||
});
|
||||
|
||||
102
packages/core/src/providers/passage.ts
Normal file
102
packages/core/src/providers/passage.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* <div style={{backgroundColor: "#000", display: "flex", justifyContent: "space-between", color: "#fff", padding: 16}}>
|
||||
* <span>Built-in <b>Passage by 1Password</b> integration.</span>
|
||||
* <a href="https://passage.1password.com">
|
||||
* <img style={{display: "block"}} src="https://authjs.dev/img/providers/passage.svg" height="48" width="48"/>
|
||||
* </a>
|
||||
* </div>
|
||||
*
|
||||
* @module providers/passage
|
||||
*/
|
||||
|
||||
import type { OAuthConfig, OAuthUserConfig } from "./index.js"
|
||||
|
||||
/** @see [Supported Scopes](https://docs.passage.id/hosted-login/oidc-client-configuration#supported-scopes) */
|
||||
export interface PassageProfile {
|
||||
iss: string
|
||||
/** Unique identifer in Passage for the user */
|
||||
sub: string
|
||||
aud: string[]
|
||||
exp: number
|
||||
iat: number
|
||||
auth_time: number
|
||||
azp: string
|
||||
client_id: string
|
||||
at_hash: string
|
||||
c_hash: string
|
||||
/** The user's email address */
|
||||
email: string
|
||||
/** Whether the user has verified their email address */
|
||||
email_verified: boolean
|
||||
/** The user's phone number */
|
||||
phone: string
|
||||
/** Whether the user has verified their phone number */
|
||||
phone_number_verified: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Passage login to your page.
|
||||
*
|
||||
* ### Setup
|
||||
*
|
||||
* #### Callback URL
|
||||
* ```
|
||||
* https://example.com/api/auth/callback/passage
|
||||
* ```
|
||||
*
|
||||
* #### Configuration
|
||||
*```js
|
||||
* import Auth from "@auth/core"
|
||||
* import Passage from "@auth/core/providers/assage"
|
||||
*
|
||||
* const request = new Request(origin)
|
||||
* const response = await Auth(request, {
|
||||
* providers: [Passage({ clientId: PASSAGE_ID, clientSecret: PASSAGE_SECRET, issuer: PASSAGE_ISSUER })],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ### Resources
|
||||
*
|
||||
* - [Passage OIDC documentation](https://docs.passage.id/hosted-login/oidc-client-configuration)
|
||||
*
|
||||
* ### Notes
|
||||
*
|
||||
* By default, Auth.js assumes that the Passage provider is
|
||||
* based on the [Open ID Connect](https://openid.net/specs/openid-connect-core-1_0.html) specification.
|
||||
*
|
||||
* :::tip
|
||||
*
|
||||
* The Passage provider comes with a [default configuration](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/passage.ts).
|
||||
* To override the defaults for your use case, check out [customizing a built-in OAuth provider](https://authjs.dev/guides/providers/custom-provider#override-default-options).
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* :::info **Disclaimer**
|
||||
*
|
||||
* If you think you found a bug in the default configuration, you can [open an issue](https://authjs.dev/new/provider-issue).
|
||||
*
|
||||
* Auth.js strictly adheres to the specification and it cannot take responsibility for any deviation from
|
||||
* the spec by the provider. You can open an issue, but if the problem is non-compliance with the spec,
|
||||
* we might not pursue a resolution. You can ask for more help in [Discussions](https://authjs.dev/new/github-discussions).
|
||||
*
|
||||
* :::
|
||||
*/
|
||||
export default function Passage(
|
||||
config: OAuthUserConfig<PassageProfile>
|
||||
): OAuthConfig<PassageProfile> {
|
||||
return {
|
||||
id: "passage",
|
||||
name: "Passage",
|
||||
type: "oidc",
|
||||
client: { token_endpoint_auth_method: "client_secret_basic" },
|
||||
style: {
|
||||
logo: "/passage.svg",
|
||||
logoDark: "/passage.svg",
|
||||
bg: "#fff",
|
||||
bgDark: "#fff",
|
||||
text: "#000",
|
||||
textDark: "#000",
|
||||
},
|
||||
options: config,
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* <div style={{backgroundColor: "#000", display: "flex", justifyContent: "space-between", color: "#fff", padding: 16}}>
|
||||
* <span>Built-in <b>VK</b> integration.</span>
|
||||
* <a href="www.vk.com/">
|
||||
* <a href="https://vk.com/">
|
||||
* <img style={{display: "block"}} src="https://authjs.dev/img/providers/vk.svg" height="48" />
|
||||
* </a>
|
||||
* </div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* <div style={{backgroundColor: "#000", display: "flex", justifyContent: "space-between", color: "#fff", padding: 16}}>
|
||||
* <span>Built-in <b> Wikimedia</b> integration.</span>
|
||||
* <a href="www.mediawiki.org/">
|
||||
* <a href="https://mediawiki.org/">
|
||||
* <img style={{display: "block"}} src="https://authjs.dev/img/providers/wikimedia.svg" height="48" />
|
||||
* </a>
|
||||
* </div>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -1 +0,0 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
124
pnpm-lock.yaml
generated
124
pnpm-lock.yaml
generated
@@ -318,6 +318,31 @@ importers:
|
||||
firebase-tools: 11.16.1
|
||||
jest: 29.3.1
|
||||
|
||||
packages/adapter-kysely:
|
||||
specifiers:
|
||||
'@auth/core': workspace:*
|
||||
'@next-auth/adapter-test': workspace:*
|
||||
'@next-auth/tsconfig': workspace:*
|
||||
'@types/better-sqlite3': ^7.6.3
|
||||
'@types/pg': ^8.6.5
|
||||
better-sqlite3: ^8.2.0
|
||||
jest: ^27.4.3
|
||||
kysely: ^0.24.2
|
||||
mysql2: ^3.2.0
|
||||
pg: ^8.10.0
|
||||
dependencies:
|
||||
'@auth/core': link:../core
|
||||
devDependencies:
|
||||
'@next-auth/adapter-test': link:../adapter-test
|
||||
'@next-auth/tsconfig': link:../tsconfig
|
||||
'@types/better-sqlite3': 7.6.4
|
||||
'@types/pg': 8.10.2
|
||||
better-sqlite3: 8.5.0
|
||||
jest: 27.5.1
|
||||
kysely: 0.24.2
|
||||
mysql2: 3.6.0
|
||||
pg: 8.11.2
|
||||
|
||||
packages/adapter-mikro-orm:
|
||||
specifiers:
|
||||
'@auth/core': workspace:*
|
||||
@@ -10139,6 +10164,14 @@ packages:
|
||||
resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
|
||||
dev: true
|
||||
|
||||
/@types/pg/8.10.2:
|
||||
resolution: {integrity: sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw==}
|
||||
dependencies:
|
||||
'@types/node': 20.4.8
|
||||
pg-protocol: 1.5.0
|
||||
pg-types: 4.0.1
|
||||
dev: true
|
||||
|
||||
/@types/phoenix/1.5.4:
|
||||
resolution: {integrity: sha512-L5eZmzw89eXBKkiqVBcJfU1QGx9y+wurRIEgt0cuLH0hwNtVUxtx+6cu0R2STwWj468sjXyBYPYDtGclUd1kjQ==}
|
||||
|
||||
@@ -21590,6 +21623,11 @@ packages:
|
||||
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
|
||||
dev: true
|
||||
|
||||
/kysely/0.24.2:
|
||||
resolution: {integrity: sha512-+7eaTJNUYm2yRq1x+lEOZc+78TO35dTZ9b0dh49+Z9CTt2byMSbMiOKpwPlOyCAaHD4kILkAYWYZNywFlmBwRA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dev: true
|
||||
|
||||
/latest-version/5.1.0:
|
||||
resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -23801,15 +23839,30 @@ packages:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
dev: true
|
||||
|
||||
/pg-cloudflare/1.1.1:
|
||||
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/pg-connection-string/2.5.0:
|
||||
resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==}
|
||||
dev: true
|
||||
|
||||
/pg-connection-string/2.6.2:
|
||||
resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
|
||||
dev: true
|
||||
|
||||
/pg-int8/1.0.1:
|
||||
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: true
|
||||
|
||||
/pg-numeric/1.0.2:
|
||||
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/pg-pool/3.5.1_pg@8.7.3:
|
||||
resolution: {integrity: sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==}
|
||||
peerDependencies:
|
||||
@@ -23818,10 +23871,22 @@ packages:
|
||||
pg: 8.7.3
|
||||
dev: true
|
||||
|
||||
/pg-pool/3.6.1_pg@8.11.2:
|
||||
resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==}
|
||||
peerDependencies:
|
||||
pg: '>=8.0'
|
||||
dependencies:
|
||||
pg: 8.11.2
|
||||
dev: true
|
||||
|
||||
/pg-protocol/1.5.0:
|
||||
resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==}
|
||||
dev: true
|
||||
|
||||
/pg-protocol/1.6.0:
|
||||
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
|
||||
dev: true
|
||||
|
||||
/pg-types/2.2.0:
|
||||
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -23833,6 +23898,39 @@ packages:
|
||||
postgres-interval: 1.2.0
|
||||
dev: true
|
||||
|
||||
/pg-types/4.0.1:
|
||||
resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
pg-int8: 1.0.1
|
||||
pg-numeric: 1.0.2
|
||||
postgres-array: 3.0.2
|
||||
postgres-bytea: 3.0.0
|
||||
postgres-date: 2.0.1
|
||||
postgres-interval: 3.0.0
|
||||
postgres-range: 1.1.3
|
||||
dev: true
|
||||
|
||||
/pg/8.11.2:
|
||||
resolution: {integrity: sha512-l4rmVeV8qTIrrPrIR3kZQqBgSN93331s9i6wiUiLOSk0Q7PmUxZD/m1rQI622l3NfqBby9Ar5PABfS/SulfieQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
pg-native: '>=3.0.1'
|
||||
peerDependenciesMeta:
|
||||
pg-native:
|
||||
optional: true
|
||||
dependencies:
|
||||
buffer-writer: 2.0.0
|
||||
packet-reader: 1.0.0
|
||||
pg-connection-string: 2.6.2
|
||||
pg-pool: 3.6.1_pg@8.11.2
|
||||
pg-protocol: 1.6.0
|
||||
pg-types: 2.2.0
|
||||
pgpass: 1.0.5
|
||||
optionalDependencies:
|
||||
pg-cloudflare: 1.1.1
|
||||
dev: true
|
||||
|
||||
/pg/8.7.3:
|
||||
resolution: {integrity: sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
@@ -25032,16 +25130,33 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/postgres-array/3.0.2:
|
||||
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/postgres-bytea/1.0.0:
|
||||
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/postgres-bytea/3.0.0:
|
||||
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
obuf: 1.1.2
|
||||
dev: true
|
||||
|
||||
/postgres-date/1.0.7:
|
||||
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/postgres-date/2.0.1:
|
||||
resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/postgres-interval/1.2.0:
|
||||
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -25049,6 +25164,15 @@ packages:
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
|
||||
/postgres-interval/3.0.0:
|
||||
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/postgres-range/1.1.3:
|
||||
resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
|
||||
dev: true
|
||||
|
||||
/postgres/3.3.5:
|
||||
resolution: {integrity: sha512-+JD93VELV9gHkqpV5gdL5/70HdGtEw4/XE1S4BC8f1mcPmdib3K5XsKVbnR1XcAyC41zOnifJ+9YRKxdIsXiUw==}
|
||||
dev: true
|
||||
|
||||
46
turbo.json
46
turbo.json
@@ -2,12 +2,21 @@
|
||||
"$schema": "https://turborepo.org/schema.json",
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**/*", "*.js", "*.d.ts", "*.d.ts.map"],
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
"dist/**/*",
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
"*.d.ts.map"
|
||||
],
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"next-auth#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
"client/**",
|
||||
"core/**",
|
||||
@@ -22,7 +31,9 @@
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"@auth/core#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
"lib/**",
|
||||
"providers/**",
|
||||
@@ -35,8 +46,14 @@
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"@auth/sveltekit#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".svelte-kit/**", "client.*", "index.*"],
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
".svelte-kit/**",
|
||||
"client.*",
|
||||
"index.*"
|
||||
],
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"clean": {
|
||||
@@ -49,20 +66,28 @@
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"e2e": {
|
||||
"outputs": ["playwright-report/**"]
|
||||
"outputs": [
|
||||
"playwright-report/**"
|
||||
]
|
||||
},
|
||||
"@auth/upstash-redis-adapter#test": {
|
||||
"env": ["UPSTASH_REDIS_KEY", "UPSTASH_REDIS_URL"]
|
||||
"env": [
|
||||
"UPSTASH_REDIS_KEY",
|
||||
"UPSTASH_REDIS_URL"
|
||||
]
|
||||
},
|
||||
"docs#dev": {
|
||||
"dependsOn": [
|
||||
"@auth/core#build",
|
||||
"@auth/prisma-adapter#build",
|
||||
"@auth/solid-start#build",
|
||||
"@auth/sveltekit#build",
|
||||
"@auth/dgraph-adapter#build",
|
||||
"@auth/drizzle-adapter#build",
|
||||
"@auth/dynamodb-adapter#build",
|
||||
"@auth/fauna-adapter#build",
|
||||
"@auth/firebase-adapter#build",
|
||||
"@auth/kysely-adapter#build",
|
||||
"@auth/mikro-orm-adapter#build",
|
||||
"@auth/mongodb-adapter#build",
|
||||
"@auth/neo4j-adapter#build",
|
||||
@@ -81,11 +106,14 @@
|
||||
"dependsOn": [
|
||||
"@auth/core#build",
|
||||
"@auth/prisma-adapter#build",
|
||||
"@auth/solid-start#build",
|
||||
"@auth/sveltekit#build",
|
||||
"@auth/dgraph-adapter#build",
|
||||
"@auth/drizzle-adapter#build",
|
||||
"@auth/dynamodb-adapter#build",
|
||||
"@auth/fauna-adapter#build",
|
||||
"@auth/firebase-adapter#build",
|
||||
"@auth/kysely-adapter#build",
|
||||
"@auth/mikro-orm-adapter#build",
|
||||
"@auth/mongodb-adapter#build",
|
||||
"@auth/neo4j-adapter#build",
|
||||
@@ -107,4 +135,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user