This commit is contained in:
Skye 2023-02-22 00:32:55 +09:00
parent d1ca256f5a
commit 4b4b26a09a
Signed by: me
GPG key ID: 0104BC05F41B77B8
5 changed files with 32 additions and 178 deletions

View file

@ -1,13 +1,13 @@
{ {
"name": "@next-auth/mongodb-adapter", "name": "nextauth-mongodb-realm",
"version": "1.1.1", "version": "1.0.0",
"description": "mongoDB adapter for next-auth.", "description": "mongoDB Realm adapter for next-auth.",
"homepage": "https://authjs.dev", "homepage": "https://git.skye.vg/me/nextauth-mongodb-realm",
"repository": "https://github.com/nextauthjs/next-auth", "repository": "https://git.skye.vg/me/nextauth-mongodb-realm",
"bugs": { "bugs": {
"url": "https://github.com/nextauthjs/next-auth/issues" "url": "https://git.skye.vg/me/nextauth-mongodb-realm/issues"
}, },
"author": "Balázs Orbán <info@balazsorban.com>", "author": "Skye Green <support@skyevg.systems>",
"main": "dist/index.js", "main": "dist/index.js",
"license": "ISC", "license": "ISC",
"keywords": [ "keywords": [
@ -22,8 +22,6 @@
"access": "public" "access": "public"
}, },
"scripts": { "scripts": {
"test": "./tests/test.sh",
"test:watch": "./tests/test.sh -w",
"build": "tsc" "build": "tsc"
}, },
"files": [ "files": [
@ -31,17 +29,12 @@
"dist" "dist"
], ],
"peerDependencies": { "peerDependencies": {
"mongodb": "^4.1.1", "realm-web": "^2.0.0",
"next-auth": "^4" "next-auth": "^4"
}, },
"devDependencies": { "devDependencies": {
"@next-auth/adapter-test": "https://gitpkg.now.sh/nextauthjs/next-auth/packages/adapter-test?main",
"@next-auth/tsconfig": "https://gitpkg.now.sh/nextauthjs/next-auth/packages/tsconfig?main", "@next-auth/tsconfig": "https://gitpkg.now.sh/nextauthjs/next-auth/packages/tsconfig?main",
"jest": "^27.4.3", "realm-web": "^2.0.0",
"mongodb": "^4.4.0", "next-auth": "^4"
"next-auth": "^4.19.2"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
} }
} }

View file

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import { ObjectId } from "mongodb" import * as Realm from "realm-web";
import type { import type {
Adapter, Adapter,
@ -8,7 +8,6 @@ import type {
AdapterSession, AdapterSession,
VerificationToken, VerificationToken,
} from "next-auth/adapters" } from "next-auth/adapters"
import type { MongoClient } from "mongodb"
export interface MongoDBAdapterOptions { export interface MongoDBAdapterOptions {
collections?: { collections?: {
@ -17,7 +16,8 @@ export interface MongoDBAdapterOptions {
Sessions?: string Sessions?: string
VerificationTokens?: string VerificationTokens?: string
} }
databaseName?: string databaseName: string
serviceName: string
} }
export const defaultCollections: Required< export const defaultCollections: Required<
@ -56,31 +56,31 @@ export const format = {
else if (key === "id") continue else if (key === "id") continue
else newObject[key] = value else newObject[key] = value
} }
return newObject as T & { _id: ObjectId } return newObject as T & { _id: Realm.BSON.ObjectId }
}, },
} }
/** Converts from string to ObjectId */ /** Converts from string to ObjectId */
export function _id(hex?: string) { export function _id(hex?: string) {
if (hex?.length !== 24) return new ObjectId() if (hex?.length !== 24) return new Realm.BSON.ObjectId()
return new ObjectId(hex) return new Realm.BSON.ObjectId(hex)
} }
export function MongoDBAdapter( export function MongoDBAdapter(
client: Promise<MongoClient>, client: Promise<Realm.User>,
options: MongoDBAdapterOptions = {} options: MongoDBAdapterOptions
): Adapter { ): Adapter {
const { collections } = options const { collections } = options
const { from, to } = format const { from, to } = format
const db = (async () => { const db = (async () => {
const _db = (await client).db(options.databaseName) const _db = (await client).mongoClient(options.serviceName).db(options.databaseName)
const c = { ...defaultCollections, ...collections } const c = { ...defaultCollections, ...collections }
return { return {
U: _db.collection<AdapterUser>(c.Users), U: _db.collection<AdapterUser & { _id: Realm.BSON.ObjectId }>(c.Users),
A: _db.collection<AdapterAccount>(c.Accounts), A: _db.collection<AdapterAccount & { _id: Realm.BSON.ObjectId }>(c.Accounts),
S: _db.collection<AdapterSession>(c.Sessions), S: _db.collection<AdapterSession & { _id: Realm.BSON.ObjectId }>(c.Sessions),
V: _db.collection<VerificationToken>(c?.VerificationTokens), V: _db.collection<VerificationToken & { _id: Realm.BSON.ObjectId }>(c?.VerificationTokens),
} }
})() })()
@ -105,7 +105,7 @@ export function MongoDBAdapter(
if (!account) return null if (!account) return null
const user = await ( const user = await (
await db await db
).U.findOne({ _id: new ObjectId(account.userId) }) ).U.findOne({ _id: new Realm.BSON.ObjectId(account.userId) })
if (!user) return null if (!user) return null
return from<AdapterUser>(user) return from<AdapterUser>(user)
}, },
@ -114,9 +114,9 @@ export function MongoDBAdapter(
const result = await ( const result = await (
await db await db
).U.findOneAndUpdate({ _id }, { $set: user }, { returnDocument: "after" }) ).U.findOneAndUpdate({ _id }, { $set: user }, { returnNewDocument: true })
return from<AdapterUser>(result.value!) return from<AdapterUser>(result!)
}, },
async deleteUser(id) { async deleteUser(id) {
const userId = _id(id) const userId = _id(id)
@ -133,7 +133,7 @@ export function MongoDBAdapter(
return account return account
}, },
async unlinkAccount(provider_providerAccountId) { async unlinkAccount(provider_providerAccountId) {
const { value: account } = await ( const account = await (
await db await db
).A.findOneAndDelete(provider_providerAccountId) ).A.findOneAndDelete(provider_providerAccountId)
return from<AdapterAccount>(account!) return from<AdapterAccount>(account!)
@ -143,7 +143,7 @@ export function MongoDBAdapter(
if (!session) return null if (!session) return null
const user = await ( const user = await (
await db await db
).U.findOne({ _id: new ObjectId(session.userId) }) ).U.findOne({ _id: new Realm.BSON.ObjectId(session.userId) })
if (!user) return null if (!user) return null
return { return {
user: from<AdapterUser>(user), user: from<AdapterUser>(user),
@ -163,12 +163,12 @@ export function MongoDBAdapter(
).S.findOneAndUpdate( ).S.findOneAndUpdate(
{ sessionToken: session.sessionToken }, { sessionToken: session.sessionToken },
{ $set: session }, { $set: session },
{ returnDocument: "after" } { returnNewDocument: true }
) )
return from<AdapterSession>(result.value!) return from<AdapterSession>(result!)
}, },
async deleteSession(sessionToken) { async deleteSession(sessionToken) {
const { value: session } = await ( const session = await (
await db await db
).S.findOneAndDelete({ ).S.findOneAndDelete({
sessionToken, sessionToken,
@ -180,7 +180,7 @@ export function MongoDBAdapter(
return data return data
}, },
async useVerificationToken(identifier_token) { async useVerificationToken(identifier_token) {
const { value: verificationToken } = await ( const verificationToken = await (
await db await db
).V.findOneAndDelete(identifier_token) ).V.findOneAndDelete(identifier_token)

View file

@ -1,54 +0,0 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
import { MongoClient } from "mongodb"
const name = "custom-test"
const client = new MongoClient(`mongodb://localhost:27017/${name}`)
const clientPromise = client.connect()
const collections = { ...defaultCollections, Users: "some_userz" }
runBasicTests({
adapter: MongoDBAdapter(clientPromise, {
collections,
}),
db: {
async disconnect() {
await client.db().dropDatabase()
await client.close()
},
async user(id) {
const user = await client
.db()
.collection(collections.Users)
.findOne({ _id: _id(id) })
if (!user) return null
return format.from(user)
},
async account(provider_providerAccountId) {
const account = await client
.db()
.collection(collections.Accounts)
.findOne(provider_providerAccountId)
if (!account) return null
return format.from(account)
},
async session(sessionToken) {
const session = await client
.db()
.collection(collections.Sessions)
.findOne({ sessionToken })
if (!session) return null
return format.from(session)
},
async verificationToken(identifier_token) {
const token = await client
.db()
.collection(collections.VerificationTokens)
.findOne(identifier_token)
if (!token) return null
const { _id, ...rest } = token
return rest
},
},
})

View file

@ -1,51 +0,0 @@
import { runBasicTests } from "@next-auth/adapter-test"
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
import { MongoClient } from "mongodb"
const name = "test"
const client = new MongoClient(`mongodb://localhost:27017/${name}`)
const clientPromise = client.connect()
runBasicTests({
adapter: MongoDBAdapter(clientPromise),
db: {
async disconnect() {
await client.db().dropDatabase()
await client.close()
},
async user(id) {
const user = await client
.db()
.collection(defaultCollections.Users)
.findOne({ _id: _id(id) })
if (!user) return null
return format.from(user)
},
async account(provider_providerAccountId) {
const account = await client
.db()
.collection(defaultCollections.Accounts)
.findOne(provider_providerAccountId)
if (!account) return null
return format.from(account)
},
async session(sessionToken) {
const session = await client
.db()
.collection(defaultCollections.Sessions)
.findOne({ sessionToken })
if (!session) return null
return format.from(session)
},
async verificationToken(identifier_token) {
const token = await client
.db()
.collection(defaultCollections.VerificationTokens)
.findOne(identifier_token)
if (!token) return null
const { _id, ...rest } = token
return rest
},
},
})

View file

@ -1,34 +0,0 @@
#!/usr/bin/env bash
CONTAINER_NAME=next-auth-mongodb-test
JEST_WATCH=false
# Is the watch flag passed to the script?
while getopts w flag
do
case "${flag}" in
w) JEST_WATCH=true;;
*) continue;;
esac
done
# Start db
docker run -d --rm -p 27017:27017 --name ${CONTAINER_NAME} mongo
echo "Waiting 3 sec for db to start..."
sleep 3
if $JEST_WATCH; then
# Run jest in watch mode
npx jest tests --watch
# Only stop the container after jest has been quit
docker stop "${CONTAINER_NAME}"
else
# Always stop container, but exit with 1 when tests are failing
if npx jest;then
docker stop ${CONTAINER_NAME}
else
docker stop ${CONTAINER_NAME} && exit 1
fi
fi