Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(provider): require to import every provider individually #2518

Merged
merged 14 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ node_modules
.docusaurus
.cache-loader
www/providers.json
src/providers/index.js
/internals
/providers
/types/providers/*
!types/providers/index.d.ts
!types/providers/email.d.ts
!types/providers/credentials.d.ts
!types/providers/oauth.d.ts
/adapters.d.ts
/adapters.js
/client.d.ts
Expand All @@ -36,8 +41,6 @@ src/providers/index.js
/index.js
/jwt.d.ts
/jwt.js
/providers.d.ts
/providers.js
/errors.js
/errors.d.ts
/react.js
Expand Down
52 changes: 33 additions & 19 deletions config/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const path = require("path")
const MODULE_ENTRIES = {
SERVER: "index",
REACT: "react",
PROVIDERS: "providers",
ADAPTERS: "adapters",
JWT: "jwt",
ERRORS: "errors",
Expand All @@ -17,8 +16,6 @@ const BUILD_TARGETS = {
"module.exports = require('./dist/server').default\n",
[`${MODULE_ENTRIES.REACT}.js`]:
"module.exports = require('./dist/client/react').default\n",
[`${MODULE_ENTRIES.PROVIDERS}.js`]:
"module.exports = require('./dist/providers').default\n",
[`${MODULE_ENTRIES.JWT}.js`]:
"module.exports = require('./dist/lib/jwt').default\n",
[`${MODULE_ENTRIES.ERRORS}.js`]:
Expand All @@ -33,12 +30,13 @@ Object.entries(BUILD_TARGETS).forEach(([target, content]) => {
})

// Building types
fs.mkdirSync("providers", { recursive: true })

const TYPES_TARGETS = [
`${MODULE_ENTRIES.SERVER}.d.ts`,
`${MODULE_ENTRIES.REACT}-client.d.ts`,
`${MODULE_ENTRIES.ADAPTERS}.d.ts`,
`${MODULE_ENTRIES.PROVIDERS}.d.ts`,
"providers",
`${MODULE_ENTRIES.JWT}.d.ts`,
`${MODULE_ENTRIES.ERRORS}.d.ts`,
"internals",
Expand All @@ -53,23 +51,24 @@ TYPES_TARGETS.forEach((target) => {
),
(err) => {
if (err) throw err
console.log(`[build-types] copying "${target}" to root folder`)
console.log(`[types] copying "${target}" to root folder`)
}
)
})

// Building providers
// Generate provider types

const providersDir = path.join(process.cwd(), "/src/providers")
const providersDirPath = path.join(process.cwd(), "/src/providers")

const files = fs
.readdirSync(providersDir, "utf8")
.filter((file) => file !== "index.js")
const oauthProviderFiles = fs
.readdirSync(providersDirPath, "utf8")
.filter((f) => f !== "credentials.js" && f !== "email.js")

let importLines = ""
let exportLines = `export default {\n`
files.forEach((file) => {
const provider = fs.readFileSync(path.join(providersDir, file), "utf8")
let type = `export type OAuthProviderType =\n`

oauthProviderFiles.forEach((file) => {
const provider = fs.readFileSync(path.join(providersDirPath, file), "utf8")
const fileName = file.split(".")[0]
try {
// NOTE: If this fails, the default export probably wasn't a named function.
// Always use a named function as default export.
Expand All @@ -78,8 +77,24 @@ files.forEach((file) => {
/export default function (?<functionName>.+)\s?\(/
).groups

importLines += `import ${functionName} from "./${file}"\n`
exportLines += ` ${functionName},\n`
type += ` | "${functionName}"\n`
const providerModule = `import { OAuthConfig } from "."

declare module "next-auth/providers/${fileName}" {
export default function ${functionName}Provider(
options: Partial<OAuthConfig>
): OAuthConfig
}
`

fs.writeFile(
path.join("types/providers", `${fileName}.d.ts`),
providerModule
)

console.log(
`[types] created module declaration for "${functionName}" provider`
)
} catch (error) {
console.error(
[
Expand All @@ -90,9 +105,8 @@ files.forEach((file) => {
process.exit(1)
}
})
exportLines += `}\n`

fs.writeFile(
path.join(process.cwd(), "src/providers/index.js"),
[importLines, exportLines].join("\n")
path.join(process.cwd(), "types/providers/oauth-providers.d.ts"),
type
)
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
".": "./dist/server/index.js",
"./jwt": "./dist/lib/jwt.js",
"./react": "./dist/client/react.js",
"./providers": "./dist/providers/index.js",
"./providers/*": "./dist/providers/*.js",
"./errors": "./dist/lib/errors.js"
},
Expand All @@ -49,8 +48,7 @@
"dist",
"index.js",
"index.d.ts",
"providers.js",
"providers.d.ts",
"providers",
"adapters.js",
"adapters.d.ts",
"react.js",
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"next-auth/adapters": ["./src/adapters"],
"next-auth/react": ["./src/client/react"],
"next-auth/jwt": ["./src/lib/jwt"],
"next-auth/providers": ["./src/providers"],
"next-auth/providers/*": ["./src/providers/*"],
},
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
Expand Down
34 changes: 34 additions & 0 deletions types/providers/credentials.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Awaitable, NextApiRequest } from "../internals/utils"
import { CommonProviderOptions } from "."
import { User } from ".."

export interface CredentialInput {
label?: string
type?: string
value?: string
placeholder?: string
}

export type Credentials = Record<string, CredentialInput>

export interface CredentialsConfig<C extends Credentials = {}>
extends CommonProviderOptions {
type: "credentials"
credentials: C
authorize(
credentials: Record<keyof C, string>,
req: NextApiRequest
): Awaitable<User | null>
}

export type CredentialsProvider = <C extends Record<string, CredentialInput>>(
options: Partial<CredentialsConfig<C>>
) => CredentialsConfig<C>

export type CredentialsProviderType = "Credentials"

declare module "next-auth/providers/credentials" {
export default function CredentialsProvider<
C extends Record<string, CredentialInput>
>(options: Partial<CredentialsConfig<C>>): CredentialsConfig<C>
}
38 changes: 38 additions & 0 deletions types/providers/email.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { CommonProviderOptions } from "."
import { Options as SMTPConnectionOptions } from "nodemailer/lib/smtp-connection"
import { Awaitable } from "../internals/utils"

export type SendVerificationRequest = (params: {
identifier: string
url: string
baseUrl: string
token: string
provider: EmailConfig
}) => Awaitable<void>

export interface EmailConfig extends CommonProviderOptions {
type: "email"
// TODO: Make use of https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html
server: string | SMTPConnectionOptions
/** @default "NextAuth <no-reply@example.com>" */
from?: string
/**
* How long until the e-mail can be used to log the user in,
* in seconds. Defaults to 1 day
* @default 86400
*/
maxAge?: number
sendVerificationRequest: SendVerificationRequest
}

export type EmailProvider = (options: Partial<EmailConfig>) => EmailConfig

// TODO: Rename to Token provider
// when started working on https://github.com/nextauthjs/next-auth/discussions/1465
export type EmailProviderType = "Email"

declare module "next-auth/providers/email" {
export default function EmailProvider(
options: Partial<EmailConfig>
): EmailConfig
}
36 changes: 36 additions & 0 deletions types/providers/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { OAuthConfig, OAuthProvider, OAuthProviderType } from "./oauth"

import { EmailConfig, EmailProvider, EmailProviderType } from "./email"

import {
CredentialsConfig,
CredentialsProvider,
CredentialsProviderType,
} from "./credentials"

export * from "./oauth"
export * from "./email"
export * from "./credentials"

export type ProviderType = "oauth" | "email" | "credentials"

export interface CommonProviderOptions {
id: string
name: string
type: ProviderType
}

export type Provider = OAuthConfig | EmailConfig | CredentialsConfig

export type BuiltInProviders = Record<OAuthProviderType, OAuthProvider> &
Record<CredentialsProviderType, CredentialsProvider> &
Record<EmailProviderType, EmailProvider>

export type AppProviders = Array<
Provider | ReturnType<BuiltInProviders[keyof BuiltInProviders]>
>

export interface AppProvider extends CommonProviderOptions {
signinUrl: string
callbackUrl: string
}
Loading