mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
17 Commits
@auth/core
...
@auth/core
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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/**/*"]
|
||||
|
||||
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*
|
||||
|
||||
@@ -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 |
@@ -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.2.1",
|
||||
"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
|
||||
*
|
||||
@@ -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("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 const accounts = mysqlTable(
|
||||
"accounts",
|
||||
{
|
||||
const accounts = mySqlTable(
|
||||
"accounts",
|
||||
{
|
||||
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("sessions", {
|
||||
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()
|
||||
|
||||
@@ -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("users", {
|
||||
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(
|
||||
"accounts",
|
||||
{
|
||||
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("sessions", {
|
||||
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
|
||||
|
||||
@@ -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("users", {
|
||||
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(
|
||||
"accounts",
|
||||
{
|
||||
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("sessions", {
|
||||
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
|
||||
|
||||
@@ -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.10.2",
|
||||
"description": "Authentication for the Web.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
|
||||
@@ -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