Compare commits

..

4 Commits

Author SHA1 Message Date
GitHub Actions
0f4d43e9ad chore(release): bump package version(s) [skip ci] 2023-02-05 13:52:31 +00:00
Thang Vu
28583b8ab0 feat: drop crypto dependency, convert to ESM (#6603)
Co-authored-by: Balázs Orbán <info@balazsorban.com>

BREAKING CHANGE:
- This package now only ships ESM, as all maintained Node.js versions have native support
- Dropped the `crypto` Node.js import in favor of `uuid`. When `globalThis.crypto` is the default in the future, we can remove `uuid` again
2023-02-05 14:44:33 +01:00
Balázs Orbán
1e7538a955 fix: publish .d.ts.map, add experimental warning 2023-02-05 14:42:07 +01:00
Wyatt Ades
4258857e52 feat(adapters): move to firebase-admin in Firebase Adapter (#6225)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
fixes https://github.com/nextauthjs/next-auth/issues/5049
closes https://github.com/nextauthjs/next-auth/pull/6230
closes https://github.com/nextauthjs/next-auth/pull/5449
closes https://github.com/nextauthjs/next-auth/pull/5055
fixes https://github.com/nextauthjs/next-auth/issues/4927

BREAKING CHANGE:
The adapter now expects `firebase-admin` instead of the `firebase` package and also supports either passing a config object or a firestore instance.
2023-02-05 14:41:20 +01:00
9 changed files with 131 additions and 103 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "@next-auth/dynamodb-adapter",
"repository": "https://github.com/nextauthjs/next-auth",
"version": "1.2.0",
"version": "3.0.0",
"description": "AWS DynamoDB adapter for next-auth.",
"keywords": [
"next-auth",
@@ -9,11 +9,18 @@
"oauth",
"dynamodb"
],
"type": "module",
"types": "./index.d.ts",
"homepage": "https://authjs.dev",
"bugs": {
"url": "https://github.com/nextauthjs/next-auth/issues"
},
"main": "dist/index.js",
"exports": {
".": {
"types": "./index.d.ts",
"import": "./index.js"
}
},
"private": false,
"publishConfig": {
"access": "public"
@@ -26,7 +33,10 @@
},
"files": [
"README.md",
"dist"
"index.js",
"index.d.ts",
"index.d.ts.map",
"src"
],
"author": "Pol Marnette",
"license": "ISC",
@@ -41,7 +51,11 @@
"@next-auth/adapter-test": "workspace:*",
"@next-auth/tsconfig": "workspace:*",
"@shelf/jest-dynamodb": "^2.1.0",
"@types/uuid": "^9.0.0",
"jest": "^27.4.3",
"next-auth": "workspace:*"
},
"dependencies": {
"uuid": "^9.0.0"
}
}

View File

@@ -1,4 +1,4 @@
import { randomBytes } from "crypto"
import { v4 as uuid } from "uuid"
import type {
BatchWriteCommandInput,
@@ -12,16 +12,12 @@ import type {
VerificationToken,
} from "next-auth/adapters"
import { format, generateUpdateExpression } from "./utils"
export { format, generateUpdateExpression }
export interface DynamoDBAdapterOptions {
tableName?: string,
partitionKey?: string,
sortKey?: string,
indexName?: string,
indexPartitionKey?: string,
tableName?: string
partitionKey?: string
sortKey?: string
indexName?: string
indexPartitionKey?: string
indexSortKey?: string
}
@@ -30,17 +26,17 @@ export function DynamoDBAdapter(
options?: DynamoDBAdapterOptions
): Adapter {
const TableName = options?.tableName ?? "next-auth"
const pk = options?.partitionKey ?? 'pk'
const sk = options?.sortKey ?? 'sk'
const IndexName = options?.indexName ?? 'GSI1'
const GSI1PK = options?.indexPartitionKey ?? 'GSI1PK'
const GSI1SK = options?.indexSortKey ?? 'GSI1SK'
const pk = options?.partitionKey ?? "pk"
const sk = options?.sortKey ?? "sk"
const IndexName = options?.indexName ?? "GSI1"
const GSI1PK = options?.indexPartitionKey ?? "GSI1PK"
const GSI1SK = options?.indexSortKey ?? "GSI1SK"
return {
async createUser(data) {
const user: AdapterUser = {
...(data as any),
id: randomBytes(16).toString("hex"),
id: uuid(),
}
await client.put({
@@ -50,8 +46,8 @@ export function DynamoDBAdapter(
[pk]: `USER#${user.id}`,
[sk]: `USER#${user.id}`,
type: "USER",
[GSI1PK]: `USER#${user.email as string}`,
[GSI1SK]: `USER#${user.email as string}`,
[GSI1PK]: `USER#${user.email}`,
[GSI1SK]: `USER#${user.email}`,
}),
})
@@ -165,7 +161,7 @@ export function DynamoDBAdapter(
async linkAccount(data) {
const item = {
...data,
id: randomBytes(16).toString("hex"),
id: uuid(),
[pk]: `USER#${data.userId}`,
[sk]: `ACCOUNT#${data.provider}#${data.providerAccountId}`,
[GSI1PK]: `ACCOUNT#${data.provider}`,
@@ -229,7 +225,7 @@ export function DynamoDBAdapter(
},
async createSession(data) {
const session = {
id: randomBytes(16).toString("hex"),
id: uuid(),
...data,
}
await client.put({
@@ -327,3 +323,73 @@ export function DynamoDBAdapter(
},
}
}
// 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))
}
const format = {
/** Takes a plain old JavaScript object and turns it into a Dynamodb object */
to(object: Record<string, any>) {
const newObject: Record<string, unknown> = {}
for (const key in object) {
const value = object[key]
if (value instanceof Date) {
// DynamoDB requires the TTL attribute be a UNIX timestamp (in secs).
if (key === "expires") newObject[key] = value.getTime() / 1000
else newObject[key] = value.toISOString()
} else newObject[key] = value
}
return newObject
},
/** Takes a Dynamo object and returns a plain old JavaScript object */
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null {
if (!object) return null
const newObject: Record<string, unknown> = {}
for (const key in object) {
// Filter DynamoDB specific attributes so it doesn't get passed to core,
// to avoid revealing the type of database
if (["pk", "sk", "GSI1PK", "GSI1SK"].includes(key)) continue
const value = object[key]
if (isDate(value)) newObject[key] = new Date(value)
// hack to keep type property in account
else if (key === "type" && ["SESSION", "VT", "USER"].includes(value))
continue
// The expires property is stored as a UNIX timestamp in seconds, but
// JavaScript needs it in milliseconds, so multiply by 1000.
else if (key === "expires" && typeof value === "number")
newObject[key] = new Date(value * 1000)
else newObject[key] = value
}
return newObject as T
},
}
function generateUpdateExpression(object: Record<string, any>): {
UpdateExpression: string
ExpressionAttributeNames: Record<string, string>
ExpressionAttributeValues: Record<string, unknown>
} {
const formatedSession = format.to(object)
let UpdateExpression = "set"
const ExpressionAttributeNames: Record<string, string> = {}
const ExpressionAttributeValues: Record<string, unknown> = {}
for (const property in formatedSession) {
UpdateExpression += ` #${property} = :${property},`
ExpressionAttributeNames["#" + property] = property
ExpressionAttributeValues[":" + property] = formatedSession[property]
}
UpdateExpression = UpdateExpression.slice(0, -1)
return {
UpdateExpression,
ExpressionAttributeNames,
ExpressionAttributeValues,
}
}
export { format, generateUpdateExpression }

View File

@@ -1,67 +0,0 @@
// 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 Dynamodb object */
to(object: Record<string, any>) {
const newObject: Record<string, unknown> = {}
for (const key in object) {
const value = object[key]
if (value instanceof Date) {
// DynamoDB requires the TTL attribute be a UNIX timestamp (in secs).
if (key === "expires") newObject[key] = value.getTime() / 1000
else newObject[key] = value.toISOString()
} else newObject[key] = value
}
return newObject
},
/** Takes a Dynamo object and returns a plain old JavaScript object */
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null {
if (!object) return null
const newObject: Record<string, unknown> = {}
for (const key in object) {
// Filter DynamoDB specific attributes so it doesn't get passed to core,
// to avoid revealing the type of database
if (["pk", "sk", "GSI1PK", "GSI1SK"].includes(key)) continue
const value = object[key]
if (isDate(value)) newObject[key] = new Date(value)
// hack to keep type property in account
else if (key === "type" && ["SESSION", "VT", "USER"].includes(value))
continue
// The expires property is stored as a UNIX timestamp in seconds, but
// JavaScript needs it in milliseconds, so multiply by 1000.
else if (key === "expires" && typeof value === "number")
newObject[key] = new Date(value * 1000)
else newObject[key] = value
}
return newObject as T
},
}
export function generateUpdateExpression(object: Record<string, any>): {
UpdateExpression: string
ExpressionAttributeNames: Record<string, string>
ExpressionAttributeValues: Record<string, unknown>
} {
const formatedSession = format.to(object)
let UpdateExpression = "set"
const ExpressionAttributeNames: Record<string, string> = {}
const ExpressionAttributeValues: Record<string, unknown> = {}
for (const property in formatedSession) {
UpdateExpression += ` #${property} = :${property},`
ExpressionAttributeNames["#" + property] = property
ExpressionAttributeValues[":" + property] = formatedSession[property]
}
UpdateExpression = UpdateExpression.slice(0, -1)
return {
UpdateExpression,
ExpressionAttributeNames,
ExpressionAttributeValues,
}
}

View File

@@ -1,4 +1,4 @@
import { format } from "../src/utils"
import { format } from "../src/"
describe("dynamodb utils.format", () => {
it("format.to() preserves non-Date non-expires properties", () => {

View File

@@ -2,7 +2,15 @@
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
"outDir": ".",
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"skipDefaultLibCheck": true,
"strictNullChecks": true,
"stripInternal": true,
"declarationMap": true,
"declaration": true
},
"exclude": ["tests", "dist", "jest.config.js", "jest-dynamodb-config.js"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/firebase-adapter",
"version": "1.0.3",
"version": "2.0.0",
"description": "Firebase adapter for next-auth.",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
@@ -52,4 +52,4 @@
"jest": "^29.3.1",
"next-auth": "workspace:*"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@auth/core",
"version": "0.3.0",
"version": "0.4.0",
"description": "Authentication for the Web.",
"keywords": [
"authentication",
@@ -27,7 +27,7 @@
"types": "./index.d.ts",
"files": [
"*.js",
"*.d.ts",
"*.d.ts*",
"lib",
"providers",
"src"
@@ -93,4 +93,4 @@
"postcss": "8.4.19",
"postcss-nested": "6.0.0"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@auth/sveltekit",
"version": "0.2.0",
"version": "0.2.1",
"description": "Authentication for SvelteKit.",
"keywords": [
"authentication",

17
pnpm-lock.yaml generated
View File

@@ -243,14 +243,19 @@ importers:
'@next-auth/adapter-test': workspace:*
'@next-auth/tsconfig': workspace:*
'@shelf/jest-dynamodb': ^2.1.0
'@types/uuid': ^9.0.0
jest: ^27.4.3
next-auth: workspace:*
uuid: ^9.0.0
dependencies:
uuid: 9.0.0
devDependencies:
'@aws-sdk/client-dynamodb': 3.113.0
'@aws-sdk/lib-dynamodb': 3.113.0_eb2z3hhrjl3qvyc6ecmpo2nhva
'@next-auth/adapter-test': link:../adapter-test
'@next-auth/tsconfig': link:../tsconfig
'@shelf/jest-dynamodb': 2.2.4_qsruu6yolbxs4rh6ixjhkibvwu
'@types/uuid': 9.0.0
jest: 27.5.1
next-auth: link:../next-auth
@@ -12750,6 +12755,10 @@ packages:
resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==}
dev: true
/@types/uuid/9.0.0:
resolution: {integrity: sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==}
dev: true
/@types/validator/13.7.3:
resolution: {integrity: sha512-DNviAE5OUcZ5s+XEQHRhERLg8fOp8gSgvyJ4aaFASx5wwaObm+PBwTIMXiOFm1QrSee5oYwEAYb7LMzX2O88gA==}
dev: true
@@ -13741,10 +13750,8 @@ packages:
indent-string: 4.0.0
dev: true
/ajv-formats/2.1.1_ajv@8.11.0:
/ajv-formats/2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta:
ajv:
optional: true
@@ -19535,7 +19542,7 @@ packages:
dependencies:
'@apidevtools/json-schema-ref-parser': 9.0.9
ajv: 8.11.0
ajv-formats: 2.1.1_ajv@8.11.0
ajv-formats: 2.1.1
body-parser: 1.20.0
content-type: 1.0.4
deep-freeze: 0.0.1
@@ -30975,7 +30982,7 @@ packages:
dependencies:
'@types/json-schema': 7.0.11
ajv: 8.11.0
ajv-formats: 2.1.1_ajv@8.11.0
ajv-formats: 2.1.1
ajv-keywords: 5.1.0_ajv@8.11.0
dev: true