Skip to content

Commit

Permalink
feat: introduce @auth/neo4j-adapter (#7804)
Browse files Browse the repository at this point in the history
Database adapters are not dependent on Next.js features, so it makes sense to republish them under the `@auth/*` scope.

This PR is part of a series to convert adapters, using `@auth/core` for types.

BREAKING CHANGE:
If you are coming from the previous adapter, change your `package.json`:

```diff
-  "@next-auth/neo4j-adapter": "0.0.0",
+  "@auth/neo4j-adapter": "0.0.0",
```

And run `npm install`, `yarn install` or `pnpm install` respectively.

**Note:** This packages is published as ESM-only

This package assumes that `globalThis.crypto` is available.

In older Node.js versions, you can polyfill by adding:

`globalThis.crypto ??= require("node:crypto").webcrypto`
  • Loading branch information
balazsorban44 committed Jun 14, 2023
1 parent 8a0b11f commit 6e4516a
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/3_bug_adapter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ body:
- "@auth/firebase-adapter"
- "@auth/mikro-orm-adapter"
- "@auth/mongodb-adapter"
- "@next-auth/neo4j-adapter"
- "@auth/neo4j-adapter"
- "@next-auth/pouchdb-adapter"
- "@auth/prisma-adapter"
- "@next-auth/sequelize-adapter"
Expand Down
2 changes: 1 addition & 1 deletion .github/issue-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mongodb:
- "@auth/mongodb-adapter"

neo4j:
- "@next-auth/neo4j-adapter"
- "@auth/neo4j-adapter"

pouchdb:
- "@next-auth/pouchdb-adapter"
Expand Down
10 changes: 5 additions & 5 deletions packages/adapter-neo4j/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
</a>
<h3 align="center"><b>Neo4j Adapter</b> - NextAuth.js / Auth.js</a></h3>
<p align="center" style="align: center;">
<a href="https://npm.im/@next-auth/neo4j-adapter">
<a href="https://npm.im/@auth/neo4j-adapter">
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
</a>
<a href="https://npm.im/@next-auth/neo4j-adapter">
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/neo4j-adapter?color=green&label=@next-auth/neo4j-adapter&style=flat-square">
<a href="https://npm.im/@auth/neo4j-adapter">
<img alt="npm" src="https://img.shields.io/npm/v/@auth/neo4j-adapter?color=green&label=@auth/neo4j-adapter&style=flat-square">
</a>
<a href="https://www.npmtrends.com/@next-auth/neo4j-adapter">
<img src="https://img.shields.io/npm/dm/@next-auth/neo4j-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
<a href="https://www.npmtrends.com/@auth/neo4j-adapter">
<img src="https://img.shields.io/npm/dm/@auth/neo4j-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" />
Expand Down
34 changes: 20 additions & 14 deletions packages/adapter-neo4j/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@next-auth/neo4j-adapter",
"version": "1.0.6",
"description": "neo4j adapter for next-auth.",
"name": "@auth/neo4j-adapter",
"version": "0.0.0",
"description": "neo4j adapter for Auth.js",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
"bugs": {
Expand All @@ -11,7 +11,19 @@
"contributors": [
"Balázs Orbán <info@balazsorban.com>"
],
"main": "dist/index.js",
"type": "module",
"types": "./index.d.ts",
"files": [
"*.js",
"*.d.ts*",
"src"
],
"exports": {
".": {
"types": "./index.d.ts",
"import": "./index.js"
}
},
"license": "ISC",
"keywords": [
"next-auth",
Expand All @@ -28,26 +40,20 @@
"test": "./tests/test.sh",
"build": "tsc"
},
"files": [
"README.md",
"dist"
],
"peerDependencies": {
"neo4j-driver": "^4.0.0 || ^5.7.0",
"next-auth": "^4"
"neo4j-driver": "^4.0.0 || ^5.7.0"
},
"devDependencies": {
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@types/uuid": "^8.3.3",
"jest": "^27.4.3",
"neo4j-driver": "^5.7.0",
"next-auth": "workspace:*"
"neo4j-driver": "^5.7.0"
},
"dependencies": {
"uuid": "^8.3.2"
"@auth/core": "workspace:*"
},
"jest": {
"preset": "@next-auth/adapter-test/jest"
}
}
}
82 changes: 72 additions & 10 deletions packages/adapter-neo4j/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@
* ## Installation
*
* ```bash npm2yarn2pnpm
* npm install next-auth @next-auth/neo4j-adapter neo4j-driver
* npm install @auth/neo4j-adapter neo4j-driver
* ```
*
* @module @next-auth/neo4j-adapter
* @module @auth/neo4j-adapter
*/
import type { Session } from "neo4j-driver"
import type { Adapter } from "next-auth/adapters"
import { v4 as uuid } from "uuid"

import { client, format } from "./utils"
export { format }
import { type Session, isInt, integer } from "neo4j-driver"
import type { Adapter } from "@auth/core/adapters"

/** This is the interface of the Neo4j adapter options. The Neo4j adapter takes a {@link https://neo4j.com/docs/bolt/current/driver-api/#driver-session Neo4j session} as its only argument. */
export interface Neo4jOptions extends Session {}
Expand All @@ -31,7 +27,7 @@ export interface Neo4jOptions extends Session {}
*
* ```javascript title="pages/api/auth/[...nextauth].js"
* import neo4j from "neo4j-driver"
* import { Neo4jAdapter } from "@next-auth/neo4j-adapter"
* import { Neo4jAdapter } from "@auth/neo4j-adapter"
*
* const driver = neo4j.driver(
* "bolt://localhost",
Expand Down Expand Up @@ -134,7 +130,7 @@ export function Neo4jAdapter(session: Session): Adapter {

return {
async createUser(data) {
const user: any = { id: uuid(), ...data }
const user = { id: crypto.randomUUID(), ...data }
await write(`CREATE (u:User $data)`, user)
return user
},
Expand Down Expand Up @@ -288,3 +284,69 @@ export function Neo4jAdapter(session: Session): Adapter {
},
}
}

// https://github.com/honeinc/is-iso-date/blob/master/index.js
const isoDateRE =
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/

function isDate(value: any) {
return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
}

export const format = {
/** Takes a plain old JavaScript object and turns it into a Neo4j compatible object */
to(object: Record<string, any>) {
const newObject: Record<string, unknown> = {}
for (const key in object) {
const value = object[key]
if (value instanceof Date) newObject[key] = value.toISOString()
else newObject[key] = value
}
return newObject
},
/** Takes a Neo4j object and returns a plain old JavaScript object */
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null {
const newObject: Record<string, unknown> = {}
if (!object) return null
for (const key in object) {
const value = object[key]
if (isDate(value)) {
newObject[key] = new Date(value)
} else if (isInt(value)) {
if (integer.inSafeRange(value)) newObject[key] = value.toNumber()
else newObject[key] = value.toString()
} else {
newObject[key] = value
}
}

return newObject as T
},
}

function client(session: Session) {
return {
/** Reads values from the database */
async read<T>(statement: string, values?: any): Promise<T | null> {
const result = await session.readTransaction((tx) =>
tx.run(statement, values)
)

return format.from<T>(result?.records[0]?.get(0)) ?? null
},
/**
* Reads/writes values from/to the database.
* Properties are available under `$data`
*/
async write<T extends Record<string, any>>(
statement: string,
values: T
): Promise<any> {
const result = await session.writeTransaction((tx) =>
tx.run(statement, { data: format.to(values) })
)

return format.from<T>(result?.records[0]?.toObject())
},
}
}
68 changes: 0 additions & 68 deletions packages/adapter-neo4j/src/utils.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/adapter-neo4j/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import statements from "./resources/statements"

import { Neo4jAdapter, format } from "../src"

globalThis.crypto ??= require("node:crypto").webcrypto

const driver = neo4j.driver(
"bolt://localhost",
neo4j.auth.basic("neo4j", "password")
Expand Down
25 changes: 21 additions & 4 deletions packages/adapter-neo4j/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
{
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
"extends": "@next-auth/tsconfig/tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
"isolatedModules": true,
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"outDir": ".",
"rootDir": "src",
"outDir": "dist"
"skipDefaultLibCheck": true,
"strictNullChecks": true,
"stripInternal": true,
"declarationMap": true,
"declaration": true
},
"exclude": ["tests", "dist", "jest.config.js"]
}
"include": [
"src/**/*"
],
"exclude": [
"*.js",
"*.d.ts",
]
}
14 changes: 6 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

1 comment on commit 6e4516a

@vercel
Copy link

@vercel vercel bot commented on 6e4516a Jun 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.