From 748d7dc8fb4d8188d81b5e171a21943369ada642 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Sun, 19 Sep 2021 17:54:03 +1000 Subject: [PATCH 01/13] Sequelize adapter --- .github/labeler.yml | 3 + packages/sequelize/CHANGELOG.md | 4 + packages/sequelize/README.md | 63 ++++++++++ packages/sequelize/jest.config.js | 1 + packages/sequelize/logo.svg | 1 + packages/sequelize/package.json | 38 ++++++ packages/sequelize/src/index.ts | 156 +++++++++++++++++++++++++ packages/sequelize/src/schema.ts | 39 +++++++ packages/sequelize/tests/index.test.ts | 45 +++++++ packages/sequelize/tsconfig.json | 8 ++ yarn.lock | 71 ++++++++++- 11 files changed, 426 insertions(+), 3 deletions(-) create mode 100644 packages/sequelize/CHANGELOG.md create mode 100644 packages/sequelize/README.md create mode 100644 packages/sequelize/jest.config.js create mode 100644 packages/sequelize/logo.svg create mode 100644 packages/sequelize/package.json create mode 100644 packages/sequelize/src/index.ts create mode 100644 packages/sequelize/src/schema.ts create mode 100644 packages/sequelize/tests/index.test.ts create mode 100644 packages/sequelize/tsconfig.json diff --git a/.github/labeler.yml b/.github/labeler.yml index 9be9e25c..9d234437 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -17,6 +17,9 @@ firebase: pouchdb: - packages/pouchdb/**/* +sequelize: + - packages/sequelize/**/* + documentation: - ./**/*.md diff --git a/packages/sequelize/CHANGELOG.md b/packages/sequelize/CHANGELOG.md new file mode 100644 index 00000000..e4d87c4d --- /dev/null +++ b/packages/sequelize/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md new file mode 100644 index 00000000..21cbb098 --- /dev/null +++ b/packages/sequelize/README.md @@ -0,0 +1,63 @@ +

+
+      +

Sequelize Adapter - NextAuth.js

+

+ Open Source. Full Stack. Own Your Data. +

+

+ CI Test + Bundle Size + @next-auth/sequelize-adapter Version +

+

+ +## Overview + +This is the Sequelize Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package. + +You can find the Sequelize schema in the docs at [next-auth.js.org/adapters/sequelize](https://next-auth.js.org/adapters/sequelize). + +## Getting Started + +1. Install `next-auth` and `@next-auth/sequelize-adapter` as well as `sequelize` and your [database driver](https://sequelize.org/master/manual/getting-started.html) of choice. + +```js +npm install next-auth @next-auth/sequeluze-adapter sequelize sqlite3 +npm install --save-dev sequelize +``` + +2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object. + +```js +import NextAuth from "next-auth" +import Providers from "next-auth/providers" +import SequelizeAdapter, { userSchema } from "@next-auth/sequelize-adapter" + +const sequelize = new Sequelize("sqlite::memory:") + +// To override the existing models, make your new models available like so: +sequelize.models.User = sequelize.define("user", { ...userSchema, ...myCustomUserSchema }) + +// For more information on each option (and a full list of options) go to +// https://next-auth.js.org/configuration/options +export default NextAuth({ + // https://next-auth.js.org/configuration/providers + providers: [ + Providers.Google({ + clientId: process.env.GOOGLE_ID, + clientSecret: process.env.GOOGLE_SECRET, + }), + ], + adapter: SequelizeAdapter(sequelize) + ... +}) +``` + +## Contributing + +We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md). + +## License + +ISC diff --git a/packages/sequelize/jest.config.js b/packages/sequelize/jest.config.js new file mode 100644 index 00000000..219c8d17 --- /dev/null +++ b/packages/sequelize/jest.config.js @@ -0,0 +1 @@ +module.exports = require("../../jest.config") diff --git a/packages/sequelize/logo.svg b/packages/sequelize/logo.svg new file mode 100644 index 00000000..ab9c11fc --- /dev/null +++ b/packages/sequelize/logo.svg @@ -0,0 +1 @@ + diff --git a/packages/sequelize/package.json b/packages/sequelize/package.json new file mode 100644 index 00000000..98a76796 --- /dev/null +++ b/packages/sequelize/package.json @@ -0,0 +1,38 @@ +{ + "name": "@next-auth/sequelize-adapter", + "version": "1.0.0", + "description": "Sequelize adapter for next-auth.", + "homepage": "https://next-auth.js.org", + "repository": "https://github.com/nextauthjs/adapters", + "bugs": { + "url": "https://github.com/nextauthjs/next-auth/issues" + }, + "author": "github.com/luke-j", + "main": "dist/index.js", + "license": "ISC", + "keywords": [ + "next-auth", + "next.js", + "oauth", + "sequelize" + ], + "private": false, + "publishConfig": { + "access": "public" + }, + "scripts": { + "test": "yarn build && jest", + "build": "tsc" + }, + "files": [ + "README.md", + "dist" + ], + "peerDependencies": { + "next-auth": ">=4", + "sequelize": "^6.6.5" + }, + "devDependencies": { + "sequelize": "^6.6.5" + } +} diff --git a/packages/sequelize/src/index.ts b/packages/sequelize/src/index.ts new file mode 100644 index 00000000..3028dbe4 --- /dev/null +++ b/packages/sequelize/src/index.ts @@ -0,0 +1,156 @@ +import type { Account as ApadterAccount } from "next-auth" +import type { + Adapter, + AdapterUser, + AdapterSession, + VerificationToken, +} from "next-auth/adapters" +import { Sequelize, Model, ModelCtor } from "sequelize" +import { + accountSchema, + userSchema, + sessionSchema, + verificationTokenSchema, +} from "./schema" + +// @see https://sequelize.org/master/manual/typescript.html +interface AccountInstance + extends Model>, + ApadterAccount {} +interface UserInstance + extends Model>, + AdapterUser {} +interface SessionInstance + extends Model>, + AdapterSession {} +interface VerificationTokenInstance + extends Model>, + VerificationToken {} + +export { accountSchema, userSchema, sessionSchema, verificationTokenSchema } + +export default function SequelizeAdapter(client: Sequelize): Adapter { + const tableOptions = { underscored: true, timestamps: false } + + const Account = + (client.models.Account as ModelCtor) || + client.define("account", accountSchema, tableOptions) + const User = + (client.models.User as ModelCtor) || + client.define("user", userSchema, tableOptions) + const Session = + (client.models.Session as ModelCtor) || + client.define("session", sessionSchema, tableOptions) + const VerificationToken = + (client.models.VerificationToken as ModelCtor) || + client.define( + "verificationToken", + verificationTokenSchema, + tableOptions + ) + + Account.belongsTo(User, { onDelete: "cascade" }) + Session.belongsTo(User, { onDelete: "cascade" }) + + return { + async createUser(user) { + return await User.create(user) + }, + async getUser(id) { + const userInstance = await User.findByPk(id) + + return userInstance?.get({ plain: true }) ?? null + }, + async getUserByEmail(email) { + const userInstance = await User.findOne({ + where: { email }, + }) + + return userInstance?.get({ plain: true }) ?? null + }, + async getUserByAccount({ provider, providerAccountId }) { + const accountInstance = await Account.findOne({ + where: { provider, providerAccountId }, + }) + + if (!accountInstance) { + return null + } + + const userInstance = await User.findByPk(accountInstance.userId) + + return userInstance?.get({ plain: true }) ?? null + }, + async updateUser(user) { + await User.update(user, { where: { id: user.id } }) + const userInstance = await User.findByPk(user.id) + + if (!userInstance) { + throw new Error("User does not exist") + } + + return userInstance + }, + async deleteUser(userId) { + const userInstance = await User.findByPk(userId) + + await User.destroy({ where: { id: userId } }) + + return userInstance + }, + async linkAccount(account) { + await Account.create(account) + }, + async unlinkAccount({ provider, providerAccountId }) { + await Account.destroy({ + where: { provider, providerAccountId }, + }) + }, + async createSession(session) { + return await Session.create(session) + }, + async getSessionAndUser(sessionToken) { + const sessionInstance = await Session.findOne({ + where: { sessionToken }, + }) + + if (!sessionInstance) { + return null + } + + const userInstance = await User.findByPk(sessionInstance.userId) + + if (!userInstance) { + return null + } + + return { + session: sessionInstance?.get({ plain: true }), + user: userInstance?.get({ plain: true }), + } + }, + async updateSession({ sessionToken, expires }) { + await Session.update( + { expires, sessionToken }, + { where: { sessionToken } } + ) + + return await Session.findOne({ where: { sessionToken } }) + }, + async deleteSession(sessionToken) { + await Session.destroy({ where: { sessionToken } }) + }, + async createVerificationToken(token) { + return await VerificationToken.create(token) + }, + async useVerificationToken({ identifier, token }) { + const tokenInstance = await VerificationToken.findOne({ + where: { identifier, token }, + }) + + await VerificationToken.destroy({ where: { identifier } }) + + return tokenInstance?.get({ plain: true }) ?? null + }, + } +} diff --git a/packages/sequelize/src/schema.ts b/packages/sequelize/src/schema.ts new file mode 100644 index 00000000..6309cfbb --- /dev/null +++ b/packages/sequelize/src/schema.ts @@ -0,0 +1,39 @@ +import { DataTypes } from "sequelize" + +export const accountSchema = { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + type: { type: DataTypes.STRING, allowNull: false }, + provider: { type: DataTypes.STRING, allowNull: false }, + providerAccountId: { type: DataTypes.STRING, allowNull: false }, + refresh_token: { type: DataTypes.STRING }, + access_token: { type: DataTypes.STRING }, + expires_at: { type: DataTypes.INTEGER }, + token_type: { type: DataTypes.STRING }, + scope: { type: DataTypes.STRING }, + id_token: { type: DataTypes.STRING }, + oauth_token_secret: { type: DataTypes.STRING }, + oauth_token: { type: DataTypes.STRING }, + session_state: { type: DataTypes.STRING }, + userId: { type: DataTypes.INTEGER }, +} + +export const userSchema = { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + name: { type: DataTypes.STRING }, + email: { type: DataTypes.STRING, unique: true }, + emailVerified: { type: DataTypes.DATE }, + image: { type: DataTypes.STRING }, +} + +export const sessionSchema = { + id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + expires: { type: DataTypes.DATE, allowNull: false }, + sessionToken: { type: DataTypes.STRING, unique: true, allowNull: false }, + userId: { type: DataTypes.INTEGER }, +} + +export const verificationTokenSchema = { + token: { type: DataTypes.STRING, primaryKey: true }, + identifier: { type: DataTypes.STRING, allowNull: false }, + expires: { type: DataTypes.DATE, allowNull: false }, +} diff --git a/packages/sequelize/tests/index.test.ts b/packages/sequelize/tests/index.test.ts new file mode 100644 index 00000000..ca92afd8 --- /dev/null +++ b/packages/sequelize/tests/index.test.ts @@ -0,0 +1,45 @@ +import { Sequelize } from "sequelize" +import { runBasicTests } from "../../../basic-tests" +import SequelizeAdapter from "../src" + +const sequelize = new Sequelize({ + logging: false, + dialect: "sqlite", + storage: ":memory:", +}) + +runBasicTests({ + adapter: SequelizeAdapter(sequelize), + db: { + connect: async () => { + return await sequelize.sync({ force: true }) + }, + verificationToken: async ({ identifier, token }) => { + const verificationToken = + await sequelize.models.verificationToken.findOne({ + where: { identifier, token }, + }) + + return verificationToken?.get({ plain: true }) || null + }, + user: async (id) => { + const user = await sequelize.models.user.findByPk(id) + + return user?.get({ plain: true }) || null + }, + account: async ({ provider, providerAccountId }) => { + const account = await sequelize.models.account.findOne({ + where: { provider, providerAccountId }, + }) + + return account?.get({ plain: true }) || null + }, + session: async (sessionToken) => { + const session = await sequelize.models.session.findOne({ + where: { sessionToken }, + }) + + return session?.get({ plain: true }) || null + }, + }, +}) diff --git a/packages/sequelize/tsconfig.json b/packages/sequelize/tsconfig.json new file mode 100644 index 00000000..4bf53b42 --- /dev/null +++ b/packages/sequelize/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "exclude": ["tests", "dist"] +} diff --git a/yarn.lock b/yarn.lock index 6b75014b..12bf0d11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3597,7 +3597,7 @@ ansicolors@~0.3.2: resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= -any-promise@^1.0.0, any-promise@^1.1.0, any-promise@~1.3.0: +any-promise@^1.0.0, any-promise@^1.1.0, any-promise@^1.3.0, any-promise@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= @@ -5512,6 +5512,11 @@ dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== +dottie@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.2.tgz#cc91c0726ce3a054ebf11c55fbc92a7f266dd154" + integrity sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg== + double-ended-queue@2.1.0-0: version "2.1.0-0" resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" @@ -7416,6 +7421,11 @@ infer-owner@^1.0.4: resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== +inflection@1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.1.tgz#c5cadd80888a90cf84c2e96e340d7edc85d5f0cb" + integrity sha512-dldYtl2WlN0QDkIDtg8+xFwOS2Tbmp12t1cHa5/YClU6ZQjTFm7B66UcVbh9NQB+HvT5BAd2t5+yKsBkw5pcqA== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -9796,7 +9806,14 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@^2.19.3: +moment-timezone@^0.5.31: + version "0.5.33" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.33.tgz#b252fd6bb57f341c9b59a5ab61a8e51a73bbd22c" + integrity sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w== + dependencies: + moment ">= 2.9.0" + +"moment@>= 2.9.0", moment@^2.19.3, moment@^2.26.0: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== @@ -12031,6 +12048,13 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +retry-as-promised@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543" + integrity sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg== + dependencies: + any-promise "^1.3.0" + retry-request@^4.0.0: version "4.2.2" resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-4.2.2.tgz#b7d82210b6d2651ed249ba3497f07ea602f1a903" @@ -12229,6 +12253,30 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +sequelize-pool@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-6.1.0.tgz#caaa0c1e324d3c2c3a399fed2c7998970925d668" + integrity sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg== + +sequelize@^6.6.5: + version "6.6.5" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.6.5.tgz#6f618e99f3df1fc81f28709e8a3139cec3ef1f0c" + integrity sha512-QyRrJrDRiwuiILqTMHUA1yWOPIL12KlfmgZ3hnzQwbMvp2vJ6fzu9bYJQB+qPMosck4mBUggY4Cjoc6Et8FBIQ== + dependencies: + debug "^4.1.1" + dottie "^2.0.0" + inflection "1.13.1" + lodash "^4.17.20" + moment "^2.26.0" + moment-timezone "^0.5.31" + retry-as-promised "^3.2.0" + semver "^7.3.2" + sequelize-pool "^6.0.0" + toposort-class "^1.0.1" + uuid "^8.1.0" + validator "^13.6.0" + wkx "^0.5.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -13225,6 +13273,11 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +toposort-class@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" + integrity sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg= + "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" @@ -13733,7 +13786,7 @@ uuid@^7.0.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.1.0, uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -13772,6 +13825,11 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +validator@^13.6.0: + version "13.6.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.6.0.tgz#1e71899c14cdc7b2068463cb24c1cc16f6ec7059" + integrity sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -13969,6 +14027,13 @@ winston@^3.0.0: triple-beam "^1.3.0" winston-transport "^4.4.0" +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== + dependencies: + "@types/node" "*" + word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" From bb0e7921bb5186b242376c6fa73fab8280b27276 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 09:16:38 +1000 Subject: [PATCH 02/13] Simplify README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Balázs Orbán --- packages/sequelize/README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index 21cbb098..9c5b6cb6 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -32,23 +32,14 @@ npm install --save-dev sequelize ```js import NextAuth from "next-auth" import Providers from "next-auth/providers" -import SequelizeAdapter, { userSchema } from "@next-auth/sequelize-adapter" +import SequelizeAdapter from "@next-auth/sequelize-adapter" const sequelize = new Sequelize("sqlite::memory:") -// To override the existing models, make your new models available like so: -sequelize.models.User = sequelize.define("user", { ...userSchema, ...myCustomUserSchema }) - // For more information on each option (and a full list of options) go to // https://next-auth.js.org/configuration/options export default NextAuth({ - // https://next-auth.js.org/configuration/providers - providers: [ - Providers.Google({ - clientId: process.env.GOOGLE_ID, - clientSecret: process.env.GOOGLE_SECRET, - }), - ], + ... adapter: SequelizeAdapter(sequelize) ... }) From 6d4f411c4e31aa9f557c88fafa3f2015d80daa79 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 09:17:24 +1000 Subject: [PATCH 03/13] Reference adapters repo in package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Balázs Orbán --- packages/sequelize/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sequelize/package.json b/packages/sequelize/package.json index 98a76796..e58f6a94 100644 --- a/packages/sequelize/package.json +++ b/packages/sequelize/package.json @@ -5,7 +5,7 @@ "homepage": "https://next-auth.js.org", "repository": "https://github.com/nextauthjs/adapters", "bugs": { - "url": "https://github.com/nextauthjs/next-auth/issues" + "url": "https://github.com/nextauthjs/adapters/issues" }, "author": "github.com/luke-j", "main": "dist/index.js", From e0b1dae22ac417ef0888f3f724f917e919e2202b Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 09:41:47 +1000 Subject: [PATCH 04/13] Add docs on updating database schema --- packages/sequelize/README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index 9c5b6cb6..6d06f88f 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -31,7 +31,6 @@ npm install --save-dev sequelize ```js import NextAuth from "next-auth" -import Providers from "next-auth/providers" import SequelizeAdapter from "@next-auth/sequelize-adapter" const sequelize = new Sequelize("sqlite::memory:") @@ -45,6 +44,29 @@ export default NextAuth({ }) ``` +## Updating the database schema + +By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to call [`sequelize.sync()`](https://sequelize.org/master/manual/model-basics.html#model-synchronization) to have sequelize create the necessary tables, foreign keys and indexes: + +```js +import NextAuth from "next-auth" +import SequelizeAdapter from "@next-auth/sequelize-adapter" + +const sequelize = new Sequelize("sqlite::memory:") +const adapter = SequelizeAdapter(sequelize) + +// Calling sync() is not recommended in production +sequelize.sync() + +// For more information on each option (and a full list of options) go to +// https://next-auth.js.org/configuration/options +export default NextAuth({ + ... + adapter + ... +}) +``` + ## Contributing We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md). From 30363a193e6439f7aa0e13f76c86ae6463d53ede Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 09:52:14 +1000 Subject: [PATCH 05/13] Use uuids over ints for ids --- packages/sequelize/src/schema.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/sequelize/src/schema.ts b/packages/sequelize/src/schema.ts index 6309cfbb..e80244ae 100644 --- a/packages/sequelize/src/schema.ts +++ b/packages/sequelize/src/schema.ts @@ -1,7 +1,11 @@ import { DataTypes } from "sequelize" export const accountSchema = { - id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, type: { type: DataTypes.STRING, allowNull: false }, provider: { type: DataTypes.STRING, allowNull: false }, providerAccountId: { type: DataTypes.STRING, allowNull: false }, @@ -14,11 +18,15 @@ export const accountSchema = { oauth_token_secret: { type: DataTypes.STRING }, oauth_token: { type: DataTypes.STRING }, session_state: { type: DataTypes.STRING }, - userId: { type: DataTypes.INTEGER }, + userId: { type: DataTypes.UUID }, } export const userSchema = { - id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, name: { type: DataTypes.STRING }, email: { type: DataTypes.STRING, unique: true }, emailVerified: { type: DataTypes.DATE }, @@ -26,10 +34,14 @@ export const userSchema = { } export const sessionSchema = { - id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, expires: { type: DataTypes.DATE, allowNull: false }, sessionToken: { type: DataTypes.STRING, unique: true, allowNull: false }, - userId: { type: DataTypes.INTEGER }, + userId: { type: DataTypes.UUID }, } export const verificationTokenSchema = { From f6b9518cdc3132f1bc018e8380472733f825d695 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 10:03:52 +1000 Subject: [PATCH 06/13] Refactor schema to models, change user-facing API --- packages/sequelize/src/index.ts | 75 ++++++++++++------- .../sequelize/src/{schema.ts => models.ts} | 8 +- 2 files changed, 52 insertions(+), 31 deletions(-) rename packages/sequelize/src/{schema.ts => models.ts} (91%) diff --git a/packages/sequelize/src/index.ts b/packages/sequelize/src/index.ts index 3028dbe4..c1a46e72 100644 --- a/packages/sequelize/src/index.ts +++ b/packages/sequelize/src/index.ts @@ -6,12 +6,9 @@ import type { VerificationToken, } from "next-auth/adapters" import { Sequelize, Model, ModelCtor } from "sequelize" -import { - accountSchema, - userSchema, - sessionSchema, - verificationTokenSchema, -} from "./schema" +import * as defaultModels from "./models" + +export { defaultModels as models } // @see https://sequelize.org/master/manual/typescript.html interface AccountInstance @@ -27,27 +24,51 @@ interface VerificationTokenInstance extends Model>, VerificationToken {} -export { accountSchema, userSchema, sessionSchema, verificationTokenSchema } - -export default function SequelizeAdapter(client: Sequelize): Adapter { - const tableOptions = { underscored: true, timestamps: false } - - const Account = - (client.models.Account as ModelCtor) || - client.define("account", accountSchema, tableOptions) - const User = - (client.models.User as ModelCtor) || - client.define("user", userSchema, tableOptions) - const Session = - (client.models.Session as ModelCtor) || - client.define("session", sessionSchema, tableOptions) - const VerificationToken = - (client.models.VerificationToken as ModelCtor) || - client.define( - "verificationToken", - verificationTokenSchema, - tableOptions - ) +interface SequelizeAdapterOptions { + models?: Partial<{ + User: ModelCtor + Account: ModelCtor + Session: ModelCtor + VerificationToken: ModelCtor + }> +} + +export default function SequelizeAdapter( + client: Sequelize, + options?: SequelizeAdapterOptions +): Adapter { + const { models } = options ?? {} + const defaultModelOptions = { underscored: true, timestamps: false } + const { User, Account, Session, VerificationToken } = { + User: + models?.User ?? + client.define( + "user", + defaultModels.User, + defaultModelOptions + ), + Account: + models?.Account ?? + client.define( + "account", + defaultModels.Account, + defaultModelOptions + ), + Session: + models?.Session ?? + client.define( + "session", + defaultModels.Session, + defaultModelOptions + ), + VerificationToken: + models?.VerificationToken ?? + client.define( + "verificationToken", + defaultModels.VerificationToken, + defaultModelOptions + ), + } Account.belongsTo(User, { onDelete: "cascade" }) Session.belongsTo(User, { onDelete: "cascade" }) diff --git a/packages/sequelize/src/schema.ts b/packages/sequelize/src/models.ts similarity index 91% rename from packages/sequelize/src/schema.ts rename to packages/sequelize/src/models.ts index e80244ae..092ad87d 100644 --- a/packages/sequelize/src/schema.ts +++ b/packages/sequelize/src/models.ts @@ -1,6 +1,6 @@ import { DataTypes } from "sequelize" -export const accountSchema = { +export const Account = { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, @@ -21,7 +21,7 @@ export const accountSchema = { userId: { type: DataTypes.UUID }, } -export const userSchema = { +export const User = { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, @@ -33,7 +33,7 @@ export const userSchema = { image: { type: DataTypes.STRING }, } -export const sessionSchema = { +export const Session = { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, @@ -44,7 +44,7 @@ export const sessionSchema = { userId: { type: DataTypes.UUID }, } -export const verificationTokenSchema = { +export const VerificationToken = { token: { type: DataTypes.STRING, primaryKey: true }, identifier: { type: DataTypes.STRING, allowNull: false }, expires: { type: DataTypes.DATE, allowNull: false }, From cd444147bb9d0d2b05bc4da8e8518fdd907d2775 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 10:08:55 +1000 Subject: [PATCH 07/13] Add docs on customizing models --- packages/sequelize/README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index 6d06f88f..3e96f2c6 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -32,6 +32,7 @@ npm install --save-dev sequelize ```js import NextAuth from "next-auth" import SequelizeAdapter from "@next-auth/sequelize-adapter" +import Sequelize from 'sequelize' const sequelize = new Sequelize("sqlite::memory:") @@ -51,6 +52,7 @@ By default, the sequelize adapter will not create tables in your database. In pr ```js import NextAuth from "next-auth" import SequelizeAdapter from "@next-auth/sequelize-adapter" +import Sequelize from 'sequelize' const sequelize = new Sequelize("sqlite::memory:") const adapter = SequelizeAdapter(sequelize) @@ -58,8 +60,6 @@ const adapter = SequelizeAdapter(sequelize) // Calling sync() is not recommended in production sequelize.sync() -// For more information on each option (and a full list of options) go to -// https://next-auth.js.org/configuration/options export default NextAuth({ ... adapter @@ -67,6 +67,29 @@ export default NextAuth({ }) ``` +## Using custom models + +Sequelize models are option to customization like so: + +```js +import NextAuth from "next-auth" +import SequelizeAdapter, { models } from "@next-auth/sequelize-adapter" +import Sequelize, { DataTypes } from 'sequelize' + +const sequelize = new Sequelize("sqlite::memory:") +const options = { + models: { + User: sequelize.define('user', { ...models.User, phoneNumber: DataTypes.STRING }) + } +} + +export default NextAuth({ + ... + adapter: SequelizeAdapter(sequelize, options) + ... +}) +``` + ## Contributing We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md). From ddeba750a120d05a267c0dc426fdf994a3c44a04 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 10:13:45 +1000 Subject: [PATCH 08/13] Simplify arguments --- packages/sequelize/tests/index.test.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/sequelize/tests/index.test.ts b/packages/sequelize/tests/index.test.ts index ca92afd8..204606db 100644 --- a/packages/sequelize/tests/index.test.ts +++ b/packages/sequelize/tests/index.test.ts @@ -14,11 +14,9 @@ runBasicTests({ connect: async () => { return await sequelize.sync({ force: true }) }, - verificationToken: async ({ identifier, token }) => { + verificationToken: async (where) => { const verificationToken = - await sequelize.models.verificationToken.findOne({ - where: { identifier, token }, - }) + await sequelize.models.verificationToken.findOne({ where }) return verificationToken?.get({ plain: true }) || null }, @@ -27,10 +25,8 @@ runBasicTests({ return user?.get({ plain: true }) || null }, - account: async ({ provider, providerAccountId }) => { - const account = await sequelize.models.account.findOne({ - where: { provider, providerAccountId }, - }) + account: async (where) => { + const account = await sequelize.models.account.findOne({ where }) return account?.get({ plain: true }) || null }, From 3b2da67238589e3b92e35616c81c40381c4e7ecf Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Mon, 20 Sep 2021 10:16:19 +1000 Subject: [PATCH 09/13] Assume user always exists in --- packages/sequelize/src/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/sequelize/src/index.ts b/packages/sequelize/src/index.ts index c1a46e72..a5b96b82 100644 --- a/packages/sequelize/src/index.ts +++ b/packages/sequelize/src/index.ts @@ -106,11 +106,8 @@ export default function SequelizeAdapter( await User.update(user, { where: { id: user.id } }) const userInstance = await User.findByPk(user.id) - if (!userInstance) { - throw new Error("User does not exist") - } - - return userInstance + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return userInstance! }, async deleteUser(userId) { const userInstance = await User.findByPk(userId) From 48961d1517a999e421bfa74058dbaa56a7d0bb5e Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Thu, 23 Sep 2021 14:07:43 +1000 Subject: [PATCH 10/13] Enable automatic sync --- packages/sequelize/README.md | 8 +- packages/sequelize/src/index.ts | 47 ++++++++- packages/sequelize/tests/index.test.ts | 128 ++++++++++++++++++++++++- 3 files changed, 174 insertions(+), 9 deletions(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index 3e96f2c6..ba8fdbb8 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -47,7 +47,7 @@ export default NextAuth({ ## Updating the database schema -By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to call [`sequelize.sync()`](https://sequelize.org/master/manual/model-basics.html#model-synchronization) to have sequelize create the necessary tables, foreign keys and indexes: +By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to pass `{ synchronize: true }` as the second option to `SequelizeAdapter` to have sequelize create the necessary tables, foreign keys and indexes: ```js import NextAuth from "next-auth" @@ -55,14 +55,10 @@ import SequelizeAdapter from "@next-auth/sequelize-adapter" import Sequelize from 'sequelize' const sequelize = new Sequelize("sqlite::memory:") -const adapter = SequelizeAdapter(sequelize) - -// Calling sync() is not recommended in production -sequelize.sync() export default NextAuth({ ... - adapter + adapter: SequelizeAdapter(sequelize, { synchronize: true }) ... }) ``` diff --git a/packages/sequelize/src/index.ts b/packages/sequelize/src/index.ts index a5b96b82..800df96e 100644 --- a/packages/sequelize/src/index.ts +++ b/packages/sequelize/src/index.ts @@ -25,6 +25,7 @@ interface VerificationTokenInstance VerificationToken {} interface SequelizeAdapterOptions { + synchronize?: boolean models?: Partial<{ User: ModelCtor Account: ModelCtor @@ -37,7 +38,7 @@ export default function SequelizeAdapter( client: Sequelize, options?: SequelizeAdapterOptions ): Adapter { - const { models } = options ?? {} + const { models, synchronize } = options ?? {} const defaultModelOptions = { underscored: true, timestamps: false } const { User, Account, Session, VerificationToken } = { User: @@ -69,20 +70,42 @@ export default function SequelizeAdapter( defaultModelOptions ), } + let _synced = false + const sync = async () => { + if (process.env.NODE_ENV !== "production" && synchronize && !_synced) { + const syncOptions = + typeof synchronize === "object" ? synchronize : undefined + + await Promise.all([ + User.sync(syncOptions), + Account.sync(syncOptions), + Session.sync(syncOptions), + VerificationToken.sync(syncOptions), + ]) + + _synced = true + } + } Account.belongsTo(User, { onDelete: "cascade" }) Session.belongsTo(User, { onDelete: "cascade" }) return { async createUser(user) { + await sync() + return await User.create(user) }, async getUser(id) { + await sync() + const userInstance = await User.findByPk(id) return userInstance?.get({ plain: true }) ?? null }, async getUserByEmail(email) { + await sync() + const userInstance = await User.findOne({ where: { email }, }) @@ -90,6 +113,8 @@ export default function SequelizeAdapter( return userInstance?.get({ plain: true }) ?? null }, async getUserByAccount({ provider, providerAccountId }) { + await sync() + const accountInstance = await Account.findOne({ where: { provider, providerAccountId }, }) @@ -103,6 +128,8 @@ export default function SequelizeAdapter( return userInstance?.get({ plain: true }) ?? null }, async updateUser(user) { + await sync() + await User.update(user, { where: { id: user.id } }) const userInstance = await User.findByPk(user.id) @@ -110,6 +137,8 @@ export default function SequelizeAdapter( return userInstance! }, async deleteUser(userId) { + await sync() + const userInstance = await User.findByPk(userId) await User.destroy({ where: { id: userId } }) @@ -117,17 +146,25 @@ export default function SequelizeAdapter( return userInstance }, async linkAccount(account) { + await sync() + await Account.create(account) }, async unlinkAccount({ provider, providerAccountId }) { + await sync() + await Account.destroy({ where: { provider, providerAccountId }, }) }, async createSession(session) { + await sync() + return await Session.create(session) }, async getSessionAndUser(sessionToken) { + await sync() + const sessionInstance = await Session.findOne({ where: { sessionToken }, }) @@ -148,6 +185,8 @@ export default function SequelizeAdapter( } }, async updateSession({ sessionToken, expires }) { + await sync() + await Session.update( { expires, sessionToken }, { where: { sessionToken } } @@ -156,12 +195,18 @@ export default function SequelizeAdapter( return await Session.findOne({ where: { sessionToken } }) }, async deleteSession(sessionToken) { + await sync() + await Session.destroy({ where: { sessionToken } }) }, async createVerificationToken(token) { + await sync() + return await VerificationToken.create(token) }, async useVerificationToken({ identifier, token }) { + await sync() + const tokenInstance = await VerificationToken.findOne({ where: { identifier, token }, }) diff --git a/packages/sequelize/tests/index.test.ts b/packages/sequelize/tests/index.test.ts index 204606db..808067c4 100644 --- a/packages/sequelize/tests/index.test.ts +++ b/packages/sequelize/tests/index.test.ts @@ -1,6 +1,6 @@ -import { Sequelize } from "sequelize" +import { Sequelize, DataTypes } from "sequelize" import { runBasicTests } from "../../../basic-tests" -import SequelizeAdapter from "../src" +import SequelizeAdapter, { models } from "../src" const sequelize = new Sequelize({ logging: false, @@ -39,3 +39,127 @@ runBasicTests({ }, }, }) + +describe("Additional Sequelize tests", () => { + describe("synchronize option", () => { + const lowercase = (strs: string[]) => + strs.map((s) => s.replace(/[^a-z]/gi, "").toLowerCase()) + + beforeEach(async () => { + await sequelize.getQueryInterface().dropAllTables() + + const { getUser } = SequelizeAdapter(sequelize, { synchronize: true }) + + await getUser("1") + }) + + test("Creates DB tables", async () => { + const tables = await sequelize.getQueryInterface().showAllSchemas() + + expect(tables).toEqual([ + { name: "users" }, + { name: "accounts" }, + { name: "sessions" }, + { name: "verification_tokens" }, + ]) + }) + + test("Correctly creates users table", async () => { + const table = await sequelize.getQueryInterface().describeTable("users") + + expect(lowercase(Object.keys(table))).toEqual( + lowercase(Object.keys(models.User)) + ) + }) + + test("Correctly creates accounts table", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("accounts") + + expect(lowercase(Object.keys(table))).toEqual( + lowercase(Object.keys(models.Account)) + ) + }) + + test("Correctly creates sessions table", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("sessions") + + expect(lowercase(Object.keys(table))).toEqual( + lowercase(Object.keys(models.Session)) + ) + }) + + test("Correctly creates verification_tokens table", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("verification_tokens") + + expect(lowercase(Object.keys(table))).toEqual( + lowercase(Object.keys(models.VerificationToken)) + ) + }) + }) + + describe("overriding models", () => { + beforeEach(async () => { + await sequelize.getQueryInterface().dropAllTables() + + const { getUser } = SequelizeAdapter(sequelize, { + synchronize: true, + models: { + User: sequelize.define("users", { + ...models.User, + someUserAttribute: { type: DataTypes.STRING }, + }), + Account: sequelize.define("accounts", { + ...models.Account, + someAccountAttribute: { type: DataTypes.STRING }, + }), + Session: sequelize.define("sessions", { + ...models.Session, + someSessionAttribute: { type: DataTypes.STRING }, + }), + VerificationToken: sequelize.define("verification_tokens", { + ...models.VerificationToken, + someVerificationTokenAttribute: { type: DataTypes.STRING }, + }), + }, + }) + + await getUser("1") + }) + + test("Custom user model", async () => { + const table = await sequelize.getQueryInterface().describeTable("users") + + expect(table.someUserAttribute).toBeDefined() + }) + + test("Custom account model", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("accounts") + + expect(table.someAccountAttribute).toBeDefined() + }) + + test("Custom session model", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("sessions") + + expect(table.someSessionAttribute).toBeDefined() + }) + + test("Custom verification_token model", async () => { + const table = await sequelize + .getQueryInterface() + .describeTable("verification_tokens") + + expect(table.someVerificationTokenAttribute).toBeDefined() + }) + }) +}) From a03a37c3fef22e6401d15d009727c19ac2ce84f0 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Tue, 5 Oct 2021 11:48:49 +1100 Subject: [PATCH 11/13] Default synchronize to true --- packages/sequelize/README.md | 15 +++++++-------- packages/sequelize/src/index.ts | 2 +- packages/sequelize/tests/index.test.ts | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index ba8fdbb8..d1c0566c 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -47,7 +47,7 @@ export default NextAuth({ ## Updating the database schema -By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to pass `{ synchronize: true }` as the second option to `SequelizeAdapter` to have sequelize create the necessary tables, foreign keys and indexes: +By default, the sequelize adapter will create the necessary tables, foreign keys and indexes in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, if you do not want the adapter to automatically create tables, you are able to pass `{ synchronize: false }` as the second option to `SequelizeAdapter` to disable this behavior: ```js import NextAuth from "next-auth" @@ -58,7 +58,7 @@ const sequelize = new Sequelize("sqlite::memory:") export default NextAuth({ ... - adapter: SequelizeAdapter(sequelize, { synchronize: true }) + adapter: SequelizeAdapter(sequelize, { synchronize: false }) ... }) ``` @@ -73,15 +73,14 @@ import SequelizeAdapter, { models } from "@next-auth/sequelize-adapter" import Sequelize, { DataTypes } from 'sequelize' const sequelize = new Sequelize("sqlite::memory:") -const options = { - models: { - User: sequelize.define('user', { ...models.User, phoneNumber: DataTypes.STRING }) - } -} export default NextAuth({ ... - adapter: SequelizeAdapter(sequelize, options) + adapter: SequelizeAdapter(sequelize, { + models: { + User: sequelize.define('user', { ...models.User, phoneNumber: DataTypes.STRING }) + } + }) ... }) ``` diff --git a/packages/sequelize/src/index.ts b/packages/sequelize/src/index.ts index 800df96e..ad12fd06 100644 --- a/packages/sequelize/src/index.ts +++ b/packages/sequelize/src/index.ts @@ -38,7 +38,7 @@ export default function SequelizeAdapter( client: Sequelize, options?: SequelizeAdapterOptions ): Adapter { - const { models, synchronize } = options ?? {} + const { models, synchronize = true } = options ?? {} const defaultModelOptions = { underscored: true, timestamps: false } const { User, Account, Session, VerificationToken } = { User: diff --git a/packages/sequelize/tests/index.test.ts b/packages/sequelize/tests/index.test.ts index 808067c4..0fd1a538 100644 --- a/packages/sequelize/tests/index.test.ts +++ b/packages/sequelize/tests/index.test.ts @@ -48,7 +48,7 @@ describe("Additional Sequelize tests", () => { beforeEach(async () => { await sequelize.getQueryInterface().dropAllTables() - const { getUser } = SequelizeAdapter(sequelize, { synchronize: true }) + const { getUser } = SequelizeAdapter(sequelize) await getUser("1") }) From 564dc8141ee151a6bdff88d0b82d724861c636c5 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Tue, 5 Oct 2021 11:53:33 +1100 Subject: [PATCH 12/13] Slightly change wording --- packages/sequelize/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sequelize/README.md b/packages/sequelize/README.md index d1c0566c..60476ad0 100644 --- a/packages/sequelize/README.md +++ b/packages/sequelize/README.md @@ -47,7 +47,9 @@ export default NextAuth({ ## Updating the database schema -By default, the sequelize adapter will create the necessary tables, foreign keys and indexes in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, if you do not want the adapter to automatically create tables, you are able to pass `{ synchronize: false }` as the second option to `SequelizeAdapter` to disable this behavior: +In development, the sequelize adapter will create the necessary tables, foreign keys and indexes in your database. In production, synchronization is disabled. Best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). + +In development, if you do not want the adapter to automatically create tables, you are able to pass `{ synchronize: false }` as the second option to `SequelizeAdapter` to disable this behavior: ```js import NextAuth from "next-auth" From 4cd4fe8f125d9d4555792e0791072c8858c4702f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Wed, 17 Nov 2021 23:21:49 +0100 Subject: [PATCH 13/13] fix: correct peer dep versioning, don't run build on test --- packages/sequelize/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sequelize/package.json b/packages/sequelize/package.json index e58f6a94..90572f52 100644 --- a/packages/sequelize/package.json +++ b/packages/sequelize/package.json @@ -21,7 +21,7 @@ "access": "public" }, "scripts": { - "test": "yarn build && jest", + "test": "jest", "build": "tsc" }, "files": [ @@ -29,7 +29,7 @@ "dist" ], "peerDependencies": { - "next-auth": ">=4", + "next-auth": ">4 || 4.0.0-beta.1 - 4.0.0-beta.x", "sequelize": "^6.6.5" }, "devDependencies": {