forked from nextauthjs/next-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Uses typeorm as works with a large number of data stores. * Compatible with common SQL, document storage & lightweight databases. * Adapter logic integrated into signup flow but not yet complete.
- Loading branch information
1 parent
3dad0cc
commit 4bf1339
Showing
11 changed files
with
1,100 additions
and
21 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
}, | ||
"license": "ISC", | ||
"dependencies": { | ||
"oauth": "^0.9.15" | ||
"oauth": "^0.9.15", | ||
"typeorm": "^0.2.24" | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import 'reflect-metadata' | ||
import { createConnection, getConnection, getManager, EntitySchema } from 'typeorm' | ||
|
||
import { Account, AccountSchema } from '../models/account' | ||
import { User, UserSchema } from '../models/user' | ||
|
||
const Default = (config) => { | ||
|
||
function debug(...args) { | ||
if (process.env.NODE_ENV === 'development') | ||
console.log(...args) | ||
} | ||
|
||
const defaultConfig = { | ||
name: 'default', | ||
autoLoadEntities: true, | ||
entities: [ | ||
new EntitySchema(AccountSchema), | ||
new EntitySchema(UserSchema) | ||
], | ||
synchronize: true, | ||
logging: false, | ||
} | ||
|
||
config = { | ||
...defaultConfig, | ||
...config | ||
} | ||
|
||
let connection = null | ||
|
||
async function getAdapter() { | ||
|
||
// Helper function to reuse / restablish connections | ||
// (useful if they drop when after being idle) | ||
async function getDatabaseConnection() { | ||
return new Promise(async resolve => { | ||
// Get current connection by name | ||
connection = getConnection(config.name) | ||
|
||
// If connection is no longer established, reconnect | ||
if (!connection.isConnected) | ||
connection = await connection.connect() | ||
|
||
resolve() | ||
}) | ||
} | ||
|
||
if (!connection) { | ||
// If no connection, create new connection | ||
try { | ||
connection = await createConnection(config) | ||
} catch (error) { | ||
if (error.name === "AlreadyHasActiveConnectionError") { | ||
// If creating connection fails because it's already | ||
// been re-established, check it's really up | ||
await getDatabaseConnection() | ||
} else { | ||
console.error('ADAPTER_CONNECTION_ERROR', error) | ||
} | ||
} | ||
} else { | ||
// If the connection object already exists, ensure it's valid | ||
await getDatabaseConnection() | ||
} | ||
|
||
// Called when a user signs in | ||
async function createUser(profile) { | ||
debug('Create user account', profile) | ||
return new Promise(async (resolve, reject) => { | ||
try { | ||
// Create user account | ||
const user = new User(profile.name, profile.email, profile.image) | ||
await getManager().save(user) | ||
resolve(user) | ||
} catch (error) { | ||
// Reject if fails | ||
console.error('CREATE_USER_ERROR', error) | ||
reject(new Error('CREATE_USER_ERROR', error)) | ||
} | ||
}) | ||
} | ||
|
||
async function updateUser(user) { | ||
debug('Update user account', user) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Save changes to user object in DB | ||
resolve(true) | ||
}) | ||
} | ||
|
||
async function getUserById(id) { | ||
debug('Get user account by ID', id) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get user from DB | ||
resolve(false) | ||
}) | ||
} | ||
|
||
async function getUserByProviderAccountId(provider, providerAccountId) { | ||
debug('Get user account by provider account ID', provider, providerAccountId) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get user from DB | ||
resolve(false) | ||
}) | ||
} | ||
|
||
async function getUserByEmail(email) { | ||
debug('Get user account by email address', email) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get user from DB | ||
resolve(false) | ||
}) | ||
} | ||
|
||
async function getUserByCredentials(credentials) { | ||
debug('Get user account by credentials', credentials) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get user from DB | ||
resolve(true) | ||
}) | ||
} | ||
|
||
|
||
async function deleteUserById(userId) { | ||
debug('Delete user account', userId) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Delete user from DB | ||
resolve(true) | ||
}) | ||
} | ||
|
||
async function linkAccount(userId, providerId, providerAccountId, refreshToken, accessToken, accessTokenExpires) { | ||
debug('Link provider account', userId, providerId, providerAccountId, refreshToken, accessToken, accessTokenExpires) | ||
return new Promise(async (resolve, reject) => { | ||
try { | ||
// Create user account | ||
const account = new Account(userId, providerId, providerAccountId, refreshToken, accessToken, accessTokenExpires) | ||
await getManager().save(account) | ||
resolve(account) | ||
} catch (error) { | ||
// Reject if fails | ||
console.error('LINK_ACCOUNT_ERROR', error) | ||
reject(new Error('LINK_ACCOUNT_ERROR', error)) | ||
} | ||
}) | ||
} | ||
|
||
async function unlinkAccount(userId, providerId, providerAccountId) { | ||
debug('Unlink provider account', userId, providerId, providerAccountId) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get current user from DB | ||
// @TODO Delete [provider] object from user object | ||
// @TODO Save changes to user object in DB | ||
resolve(true) | ||
}) | ||
} | ||
|
||
async function createSession(user) { | ||
debug('Create session for user', user) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Create session | ||
resolve(true) | ||
}) | ||
} | ||
|
||
async function getSessionById(sessionId) { | ||
debug('Get session by ID', sessionId) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Get session | ||
resolve(true) | ||
}) | ||
} | ||
|
||
async function deleteSessionById(sessionId) { | ||
debug('Delete session by ID', sessionId) | ||
return new Promise((resolve, reject) => { | ||
// @TODO Delete session | ||
resolve(true) | ||
}) | ||
} | ||
|
||
return Promise.resolve({ | ||
createUser, | ||
updateUser, | ||
getUserById, | ||
getUserByProviderAccountId, | ||
getUserByEmail, | ||
getUserByCredentials, | ||
deleteUserById, | ||
linkAccount, | ||
unlinkAccount, | ||
createSession, | ||
getSessionById, | ||
deleteSessionById | ||
}) | ||
} | ||
|
||
return { | ||
getAdapter | ||
} | ||
} | ||
|
||
export default { | ||
Default | ||
} | ||
|
||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { createHash } from 'crypto' | ||
|
||
export class Account { | ||
constructor( | ||
userId, | ||
providerId, | ||
providerAccountId, | ||
refreshToken, | ||
accessToken, | ||
accessTokenExpires | ||
) { | ||
this.id = createHash('sha256').update(`${providerId}:${providerAccountId}`).digest('hex') | ||
this.userId = userId | ||
this.providerId = providerId | ||
this.providerAccountId = providerAccountId | ||
this.refreshToken = refreshToken | ||
this.accessToken = accessToken | ||
this.accessTokenExpires = accessTokenExpires | ||
} | ||
} | ||
|
||
export const AccountSchema = { | ||
name: 'Account', | ||
target: Account, | ||
columns: { | ||
id: { | ||
primary: true, | ||
type: 'varchar', | ||
unique: true | ||
}, | ||
userId: { | ||
type: 'varchar' | ||
}, | ||
providerId: { | ||
type: 'varchar' | ||
}, | ||
providerAccountId: { | ||
type: 'varchar' | ||
}, | ||
refreshToken: { | ||
type: 'varchar', | ||
nullable: true | ||
}, | ||
accessToken: { | ||
type: 'varchar' | ||
}, | ||
accessTokenExpires: { | ||
type: 'varchar', | ||
nullable: true | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
export class User { | ||
constructor(name, email, image) { | ||
this.name = name | ||
this.email = email | ||
this.image = image | ||
} | ||
} | ||
|
||
export const UserSchema = { | ||
name: 'User', | ||
target: User, | ||
columns: { | ||
id: { | ||
primary: true, | ||
type: 'int', | ||
generated: true | ||
}, | ||
name: { | ||
type: 'varchar', | ||
nullable: true | ||
}, | ||
email: { | ||
type: 'varchar', | ||
unique: true | ||
}, | ||
image: { | ||
type: 'varchar', | ||
nullable: true | ||
} | ||
}, | ||
relations: { | ||
accounts: { | ||
target: 'Account', | ||
type: 'one-to-many' | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.