1.0.0
This commit is contained in:
parent
d1ca256f5a
commit
4b4b26a09a
5 changed files with 32 additions and 178 deletions
27
package.json
27
package.json
|
@ -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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
src/index.ts
44
src/index.ts
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -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
|
|
Loading…
Reference in a new issue