mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d30da0170f | ||
|
|
887b2985fc | ||
|
|
d2bbac1164 | ||
|
|
35583a513d | ||
|
|
665d91019f | ||
|
|
f2b816b7b9 | ||
|
|
2e770fb0bf | ||
|
|
e83e7231fb | ||
|
|
4593ec8b01 | ||
|
|
12517f629b | ||
|
|
77012bc00c | ||
|
|
60fdf26a56 | ||
|
|
0fae0c7a8e |
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -18,21 +18,23 @@ merge of your pull request!
|
||||
|
||||
## Reasoning 💡
|
||||
|
||||
What changes are being made? What feature/bug is being fixed here?
|
||||
<!-- What changes are being made? What feature/bug is being fixed here? -->
|
||||
|
||||
## Checklist 🧢
|
||||
|
||||
Feel free cross items ( like this `~[] item~` ) if they're irrelevant to your changes.
|
||||
<!-- Feel free cross items ( like this `~[] item~` ) if they're irrelevant to your changes.
|
||||
|
||||
To check an item, place an `x` in the box like so: `- [x] Documentation`.
|
||||
To check an item, place an `x` in the box like so: `- [x] Documentation`. -->
|
||||
|
||||
- [ ] Documentation
|
||||
- [ ] Tests
|
||||
- [ ] Ready to be merged
|
||||
<!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
|
||||
|
||||
<!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
|
||||
|
||||
## Affected issues 🎟
|
||||
|
||||
<!--
|
||||
Please [scout and link issues](https://github.com/nextauthjs/next-auth/issues) that might be solved by this PR.
|
||||
|
||||
If you write `"Fixes"` or `"Closes"` before the issue link like so:
|
||||
@@ -42,3 +44,5 @@ Fixes #359
|
||||
```
|
||||
|
||||
the connected issue will be automatically closed once the PR is merged and hence help with maintenance of the library 😊
|
||||
|
||||
-->
|
||||
|
||||
@@ -60,7 +60,7 @@ export default NextAuth({
|
||||
credentials: {
|
||||
password: { label: "Password", type: "password" },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
async authorize(credentials, req) {
|
||||
if (credentials.password === "password") {
|
||||
return {
|
||||
id: 1,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
module.exports = {
|
||||
presets: [["@babel/preset-env", { targets: { node: "10.13" } }]],
|
||||
plugins: [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-optional-catch-binding",
|
||||
"@babel/plugin-transform-runtime",
|
||||
],
|
||||
comments: false,
|
||||
|
||||
2911
package-lock.json
generated
2911
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -62,8 +62,8 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.14.0",
|
||||
"@next-auth/prisma-legacy-adapter": "canary",
|
||||
"@next-auth/typeorm-legacy-adapter": "canary",
|
||||
"@next-auth/prisma-legacy-adapter": "0.0.1-canary.127",
|
||||
"@next-auth/typeorm-legacy-adapter": "0.0.2-canary.129",
|
||||
"futoin-hkdf": "^1.3.2",
|
||||
"jose": "^1.27.2",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
@@ -88,9 +88,9 @@
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.8.4",
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||
"@babel/plugin-proposal-optional-catch-binding": "^7.14.2",
|
||||
"@babel/plugin-transform-runtime": "^7.13.15",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"@babel/preset-env": "^7.14.2",
|
||||
"@semantic-release/commit-analyzer": "^8.0.1",
|
||||
"@semantic-release/github": "^7.2.0",
|
||||
"@semantic-release/npm": "7.0.8",
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function Twitter(options) {
|
||||
id: profile.id_str,
|
||||
name: profile.name,
|
||||
email: profile.email,
|
||||
image: profile.profile_image_url_https.replace(/_normal\.jpg$/, ".jpg"),
|
||||
image: profile.profile_image_url_https.replace(/_normal\.(jpg|png|gif)$/, ".$1"),
|
||||
}
|
||||
},
|
||||
...options,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export default function WorkOS(options) {
|
||||
const domain = options.domain || 'api.workos.com';
|
||||
|
||||
return {
|
||||
id: 'workos',
|
||||
name: 'WorkOS',
|
||||
@@ -10,9 +12,9 @@ export default function WorkOS(options) {
|
||||
client_id: options.clientId,
|
||||
client_secret: options.clientSecret
|
||||
},
|
||||
accessTokenUrl: 'https://api.workos.com/sso/token/',
|
||||
authorizationUrl: `https://api.workos.com/sso/authorize/?response_type=code&domain=${options.domain}`,
|
||||
profileUrl: 'https://api.workos.com/sso/profile/',
|
||||
accessTokenUrl: `https://${domain}/sso/token`,
|
||||
authorizationUrl: `https://${domain}/sso/authorize?response_type=code`,
|
||||
profileUrl: `https://${domain}/sso/profile`,
|
||||
profile: (profile) => {
|
||||
return {
|
||||
...profile,
|
||||
|
||||
@@ -336,7 +336,7 @@ export default async function callback(req, res) {
|
||||
let userObjectReturnedFromAuthorizeHandler
|
||||
try {
|
||||
userObjectReturnedFromAuthorizeHandler = await provider.authorize(
|
||||
credentials
|
||||
credentials, {...req, options: {}, cookies: {}}
|
||||
)
|
||||
if (!userObjectReturnedFromAuthorizeHandler) {
|
||||
return res
|
||||
|
||||
2
types/adapters.d.ts
vendored
2
types/adapters.d.ts
vendored
@@ -49,7 +49,7 @@ export interface AdapterInstance<U = User, P = Profile, S = Session> {
|
||||
displayName?: string
|
||||
createUser(profile: P): Promise<U>
|
||||
getUser(id: string): Promise<U | null>
|
||||
getUserByEmail(email: string): Promise<U | null>
|
||||
getUserByEmail(email: string | null): Promise<U | null>
|
||||
getUserByProviderAccountId(
|
||||
providerId: string,
|
||||
providerAccountId: string
|
||||
|
||||
4
types/providers.d.ts
vendored
4
types/providers.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import { Profile, TokenSet, User } from "."
|
||||
import { Awaitable } from "./internals/utils"
|
||||
import { Awaitable, NextApiRequest } from "./internals/utils"
|
||||
|
||||
export type ProviderType = "oauth" | "email" | "credentials"
|
||||
|
||||
@@ -115,7 +115,7 @@ interface CredentialsConfig<C extends Record<string, CredentialInput> = {}>
|
||||
extends CommonProviderOptions {
|
||||
type: "credentials"
|
||||
credentials: C
|
||||
authorize(credentials: Record<keyof C, string>): Awaitable<User | null>
|
||||
authorize(credentials: Record<keyof C, string>, req: NextApiRequest): Awaitable<User | null>
|
||||
}
|
||||
|
||||
export type CredentialsProvider = (
|
||||
|
||||
@@ -5,13 +5,17 @@ title: Databases
|
||||
|
||||
NextAuth.js comes with multiple ways of connecting to a database:
|
||||
|
||||
* **TypeORM** (default)<br/>
|
||||
_The TypeORM adapter supports MySQL, Postgres, MsSql, SQLite and MongoDB databases._
|
||||
* **Prisma**<br/>
|
||||
_The Prisma 2 adapter supports MySQL, Postgres and SQLite databases._
|
||||
* **Custom Adapter**<br/>
|
||||
- **TypeORM** (default)<br/>
|
||||
_The TypeORM adapter supports MySQL, PostgreSQL, MSSQL, SQLite and MongoDB databases._
|
||||
- **Prisma**<br/>
|
||||
_The Prisma 2 adapter supports MySQL, PostgreSQL and SQLite databases._
|
||||
- **Fauna**<br/>
|
||||
_The FaunaDB adapter only supports FaunaDB._
|
||||
- **Custom Adapter**<br/>
|
||||
_A custom Adapter can be used to connect to any database._
|
||||
|
||||
> There are currently efforts in the [`nextauthjs/adapters`](https://github.com/nextauthjs/adapters) repository to get community-based DynamoDB, Sanity, PouchDB and Sequelize Adapters merged. If you are interested in any of the above, feel free to check out the PRs in the `nextauthjs/adapters` repository!
|
||||
|
||||
**This document covers the default adapter (TypeORM).**
|
||||
|
||||
See the [documentation for adapters](/schemas/adapters) to learn more about using Prisma adapter or using a custom adapter.
|
||||
@@ -27,7 +31,7 @@ You can specify database credentials as as a connection string or a [TypeORM con
|
||||
The following approaches are exactly equivalent:
|
||||
|
||||
```js
|
||||
database: 'mysql://nextauth:password@127.0.0.1:3306/database_name'
|
||||
database: "mysql://nextauth:password@127.0.0.1:3306/database_name"
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -44,13 +48,14 @@ database: {
|
||||
:::tip
|
||||
You can pass in any valid [TypeORM configuration option](https://github.com/typeorm/typeorm/blob/master/docs/using-ormconfig.md).
|
||||
|
||||
*e.g. To set a prefix for all table names you can use the **entityPrefix** option as connection string parameter:*
|
||||
_e.g. To set a prefix for all table names you can use the **entityPrefix** option as connection string parameter:_
|
||||
|
||||
```js
|
||||
'mysql://nextauth:password@127.0.0.1:3306/database_name?entityPrefix=nextauth_'
|
||||
"mysql://nextauth:password@127.0.0.1:3306/database_name?entityPrefix=nextauth_"
|
||||
|
||||
```
|
||||
|
||||
*…or as a database configuration object:*
|
||||
_…or as a database configuration object:_
|
||||
|
||||
```js
|
||||
database: {
|
||||
@@ -63,6 +68,7 @@ database: {
|
||||
entityPrefix: 'nextauth_'
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
@@ -73,15 +79,15 @@ Using SQL to create tables and columns is the recommended way to set up an SQL d
|
||||
|
||||
Check out the links below for SQL you can run to set up a database for NextAuth.js.
|
||||
|
||||
* [MySQL Schema](/schemas/mysql)
|
||||
* [Postgres Schema](/schemas/postgres)
|
||||
- [MySQL Schema](/schemas/mysql)
|
||||
- [Postgres Schema](/schemas/postgres)
|
||||
|
||||
_If you are running SQLite, MongoDB or a Document database you can skip this step._
|
||||
|
||||
Alternatively, you can also have your database configured automatically using the `synchronize: true` option:
|
||||
|
||||
```js
|
||||
database: 'mysql://nextauth:password@127.0.0.1:3306/database_name?synchronize=true'
|
||||
database: "mysql://nextauth:password@127.0.0.1:3306/database_name?synchronize=true"
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -122,7 +128,7 @@ Install module:
|
||||
#### Example
|
||||
|
||||
```js
|
||||
database: 'mysql://username:password@127.0.0.1:3306/database_name'
|
||||
database: "mysql://username:password@127.0.0.1:3306/database_name"
|
||||
```
|
||||
|
||||
### MariaDB
|
||||
@@ -133,7 +139,7 @@ Install module:
|
||||
#### Example
|
||||
|
||||
```js
|
||||
database: 'mariadb://username:password@127.0.0.1:3306/database_name'
|
||||
database: "mariadb://username:password@127.0.0.1:3306/database_name"
|
||||
```
|
||||
|
||||
### Postgres / CockroachDB
|
||||
@@ -144,13 +150,15 @@ Install module:
|
||||
#### Example
|
||||
|
||||
PostgresDB
|
||||
|
||||
```js
|
||||
database: 'postgres://username:password@127.0.0.1:5432/database_name'
|
||||
database: "postgres://username:password@127.0.0.1:5432/database_name"
|
||||
```
|
||||
|
||||
CockroachDB
|
||||
|
||||
```js
|
||||
database: 'postgres://username:password@127.0.0.1:26257/database_name'
|
||||
database: "postgres://username:password@127.0.0.1:26257/database_name"
|
||||
```
|
||||
|
||||
If the node is using Self-signed cert
|
||||
@@ -182,7 +190,7 @@ Install module:
|
||||
#### Example
|
||||
|
||||
```js
|
||||
database: 'mssql://sa:password@localhost:1433/database_name'
|
||||
database: "mssql://sa:password@localhost:1433/database_name"
|
||||
```
|
||||
|
||||
### MongoDB
|
||||
@@ -193,12 +201,12 @@ Install module:
|
||||
#### Example
|
||||
|
||||
```js
|
||||
database: 'mongodb://username:password@127.0.0.1:3306/database_name'
|
||||
database: "mongodb://username:password@127.0.0.1:3306/database_name"
|
||||
```
|
||||
|
||||
### SQLite
|
||||
|
||||
*SQLite is intended only for development / testing and not for production use.*
|
||||
_SQLite is intended only for development / testing and not for production use._
|
||||
|
||||
Install module:
|
||||
`npm i sqlite3`
|
||||
@@ -206,7 +214,7 @@ Install module:
|
||||
#### Example
|
||||
|
||||
```js
|
||||
database: 'sqlite://localhost/:memory:'
|
||||
database: "sqlite://localhost/:memory:"
|
||||
```
|
||||
|
||||
## Other databases
|
||||
|
||||
@@ -8,7 +8,7 @@ Authentication Providers in **NextAuth.js** are services that can be used to sig
|
||||
There's four ways a user can be signed in:
|
||||
|
||||
- [Using a built-in OAuth Provider](#oauth-providers) (e.g Github, Twitter, Google, etc...)
|
||||
- [Using a custom OAuth Provider](#-using-a-custom-provider)
|
||||
- [Using a custom OAuth Provider](#using-a-custom-provider)
|
||||
- [Using Email](#email-provider)
|
||||
- [Using Credentials](#credentials-provider)
|
||||
|
||||
@@ -254,12 +254,14 @@ providers: [
|
||||
username: { label: "Username", type: "text", placeholder: "jsmith" },
|
||||
password: { label: "Password", type: "password" }
|
||||
},
|
||||
async authorize(credentials) {
|
||||
const user = (credentials) => {
|
||||
async authorize(credentials, req) {
|
||||
const user = (credentials, req) => {
|
||||
// You need to provide your own logic here that takes the credentials
|
||||
// submitted and returns either a object representing a user or value
|
||||
// that is false/null if the credentials are invalid.
|
||||
// e.g. return { id: 1, name: 'J Smith', email: 'jsmith@example.com' }
|
||||
// You can also use the request object to obtain additional parameters
|
||||
// (i.e., the request IP address)
|
||||
return null
|
||||
}
|
||||
if (user) {
|
||||
@@ -282,10 +284,10 @@ The Credentials provider can only be used if JSON Web Tokens are enabled for ses
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Description | Type | Required |
|
||||
| :---------: | :-----------------------------------------------: | :------------------------------: | :------: |
|
||||
| id | Unique ID for the provider | `string` | Yes |
|
||||
| name | Descriptive name for the provider | `string` | Yes |
|
||||
| type | Type of provider, in this case `credentials` | `"credentials"` | Yes |
|
||||
| credentials | The credentials to sign-in with | `Object` | Yes |
|
||||
| authorize | Callback to execute once user is to be authorized | `(credentials) => Promise<User>` | Yes |
|
||||
| Name | Description | Type | Required |
|
||||
| :---------: | :-----------------------------------------------: | :-----------------------------------: | :------: |
|
||||
| id | Unique ID for the provider | `string` | Yes |
|
||||
| name | Descriptive name for the provider | `string` | Yes |
|
||||
| type | Type of provider, in this case `credentials` | `"credentials"` | Yes |
|
||||
| credentials | The credentials to sign-in with | `Object` | Yes |
|
||||
| authorize | Callback to execute once user is to be authorized | `(credentials, req) => Promise<User>` | Yes |
|
||||
|
||||
@@ -328,6 +328,24 @@ export default function App ({ Component, pageProps }) {
|
||||
|
||||
If you pass the `session` page prop to the `<Provider>` – as in the example above – you can avoid checking the session twice on pages that support both server and client side rendering.
|
||||
|
||||
This only works on pages where you provide the correct `pageProps`, however. This is normally done in `getInitialProps` or `getServerSideProps` like so:
|
||||
|
||||
```js title="pages/index.js"
|
||||
import { getSession } from "next-auth/client"
|
||||
|
||||
...
|
||||
|
||||
export async function getServerSideProps(ctx) {
|
||||
return {
|
||||
props: {
|
||||
session: await getSession(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If every one of your pages needs to be protected, you can do this in `_app`, otherwise you can do it on a page-by-page basis. Alternatively, there is you can do per page authentication checks client side, instead of having each auth check be blocking (SSR) by using the method described below in [alternative client session handling](#custom-client-session-handling).
|
||||
|
||||
### Options
|
||||
|
||||
The session state is automatically synchronized across all open tabs/windows and they are all updated whenever they gain or lose focus or the state changes in any of them (e.g. a user signs in or out).
|
||||
@@ -386,3 +404,72 @@ The value for `keepAlive` should always be lower than the value of the session `
|
||||
:::note
|
||||
See [**the Next.js documentation**](https://nextjs.org/docs/advanced-features/custom-app) for more information on **_app.js** in Next.js applications.
|
||||
:::
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Custom Client Session Handling
|
||||
|
||||
Due to the way Next.js handles `getServerSideProps` / `getInitialProps`, every protected page load has to make a server-side query to check if the session is valid and then generate the requested page. This alternative solution allows for showing a loading state on the initial check and every page transition afterward will be client-side, without having to check with the server and regenerate pages.
|
||||
|
||||
```js title="pages/admin.jsx"
|
||||
export default function AdminDashboard () {
|
||||
const [session] = useSession()
|
||||
// session is always non-null inside this page, all the way down the React tree.
|
||||
return "Some super secret dashboard"
|
||||
}
|
||||
|
||||
AdminDashboard.auth = true
|
||||
```
|
||||
|
||||
```jsx title="pages/_app.jsx"
|
||||
export default function App({ Component, pageProps }) {
|
||||
return (
|
||||
<SessionProvider session={pageProps.session}>
|
||||
{Component.auth
|
||||
? <Auth><Component {...pageProps} /></Auth>
|
||||
: <Component {...pageProps} />
|
||||
}
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
|
||||
function Auth({ children }) {
|
||||
const [session, loading] = useSession()
|
||||
const isUser = !!session?.user
|
||||
React.useEffect(() => {
|
||||
if (loading) return // Do nothing while loading
|
||||
if (!isUser) signIn() // If not authenticated, force log in
|
||||
}, [isUser, loading])
|
||||
|
||||
if (isUser) {
|
||||
return children
|
||||
}
|
||||
|
||||
// Session is being fetched, or no user.
|
||||
// If no user, useEffect() will redirect.
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
```
|
||||
|
||||
It can be easily be extended/modified to support something like an options object for role based authentication on pages. An example:
|
||||
|
||||
```jsx title="pages/admin.jsx"
|
||||
AdminDashboard.auth = {
|
||||
role: "admin",
|
||||
loading: <AdminLoadingSkeleton/>,
|
||||
unauthorized: "/login-with-different-user" // redirect to this url
|
||||
}
|
||||
```
|
||||
|
||||
Because of how _app is done, it won't unnecessarily contant the /api/auth/session endpoint for pages that do not require auth.
|
||||
|
||||
More information can be found in the following [Github Issue](https://github.com/nextauthjs/next-auth/issues/1210).
|
||||
|
||||
### NextAuth.js + React-Query
|
||||
|
||||
There is also an alternative client-side API library based upon [`react-query`](https://www.npmjs.com/package/react-query) available under [`nextauthjs/react-query`](https://github.com/nextauthjs/react-query).
|
||||
|
||||
If you use `react-query` in your project already, you can leverage it with NextAuth.js to handle the client-side session management for you as well. This replaces NextAuth.js's native `useSession` and `Provider` from `next-auth/client`.
|
||||
|
||||
See repository [`README`](https://github.com/nextauthjs/react-query) for more details.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ id: typescript
|
||||
title: TypeScript
|
||||
---
|
||||
|
||||
NextAuth.js comes with its own type definitions, so you can safely use it in your TypeScript projects. Even if you don't use TypeScript, IDEs like VSCode will pick this up, to provide you with a better developer experience. While you are typing, you will get suggestions about how certain objects/functions look like, and sometimes also links to documentation, examples and other useful resources.
|
||||
NextAuth.js comes with its own type definitions, so you can safely use it in your TypeScript projects. Even if you don't use TypeScript, IDEs like VSCode will pick this up, to provide you with a better developer experience. While you are typing, you will get suggestions about what certain objects/functions look like, and sometimes also links to documentation, examples and other useful resources.
|
||||
|
||||
Check out the example repository showcasing how to use `next-auth` on a Next.js application with TypeScript:
|
||||
https://github.com/nextauthjs/next-auth-typescript-example
|
||||
|
||||
@@ -39,6 +39,8 @@ The Credentials provider is specified like other providers, except that you need
|
||||
|
||||
If you throw an Error, the user will be sent to the error page with the error message as a query parameter. If throw a URL (a string), the user will be redirected to the URL.
|
||||
|
||||
The Credentials provider's `authorize()` method also provides the request object as the second parameter (see example below).
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import Providers from `next-auth/providers`
|
||||
...
|
||||
@@ -53,7 +55,7 @@ providers: [
|
||||
username: { label: "Username", type: "text", placeholder: "jsmith" },
|
||||
password: { label: "Password", type: "password" }
|
||||
},
|
||||
async authorize(credentials) {
|
||||
async authorize(credentials, req) {
|
||||
// Add logic here to look up the user from the credentials supplied
|
||||
const user = { id: 1, name: 'J Smith', email: 'jsmith@example.com' }
|
||||
|
||||
@@ -90,7 +92,7 @@ As with all providers, the order you specify them is the order they are displaye
|
||||
Providers.Credentials({
|
||||
id: 'domain-login',
|
||||
name: "Domain Account",
|
||||
async authorize(credentials) {
|
||||
async authorize(credentials, req) {
|
||||
const user = { /* add function to get user */ }
|
||||
return user
|
||||
},
|
||||
@@ -103,7 +105,7 @@ As with all providers, the order you specify them is the order they are displaye
|
||||
Providers.Credentials({
|
||||
id: 'intranet-credentials',
|
||||
name: "Two Factor Auth",
|
||||
async authorize(credentials) {
|
||||
async authorize(credentials, req) {
|
||||
const user = { /* add function to get user */ }
|
||||
return user
|
||||
},
|
||||
|
||||
@@ -7,6 +7,10 @@ title: WorkOS
|
||||
|
||||
https://workos.com/docs/sso/guide
|
||||
|
||||
## Configuration
|
||||
|
||||
https://dashboard.workos.com
|
||||
|
||||
## Options
|
||||
|
||||
The **WorkOS Provider** comes with a set of default options:
|
||||
@@ -22,10 +26,87 @@ import Providers from `next-auth/providers`
|
||||
...
|
||||
providers: [
|
||||
Providers.WorkOS({
|
||||
clientId: process.env.WORKOS_ID,
|
||||
clientSecret: process.env.WORKOS_SECRET,
|
||||
domain: process.env.WORKOS_DOMAIN
|
||||
clientId: process.env.WORKOS_CLIENT_ID,
|
||||
clientSecret: process.env.WORKOS_API_KEY,
|
||||
}),
|
||||
],
|
||||
...
|
||||
```
|
||||
|
||||
WorkOS is not an identity provider itself, but, rather, a bridge to multiple single sign-on (SSO) providers. As a result, we need to make some additional changes to authenticate users using WorkOS.
|
||||
|
||||
In order to sign a user in using WorkOS, we need to specify which WorkOS Connection to use. A common way to do this is to collect the user's email address and extract the domain.
|
||||
|
||||
This can be done using a custom login page.
|
||||
|
||||
To add a custom login page, you can use the `pages` option:
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
...
|
||||
pages: {
|
||||
signIn: '/auth/signin',
|
||||
}
|
||||
```
|
||||
|
||||
We can then add a custom login page that displays an input where the user can enter their email address. We then extract the domain from the user's email address and pass it to the `authorizationParams` parameter on the `signIn` function:
|
||||
|
||||
```jsx title="pages/auth/signin.js"
|
||||
import { getProviders, signIn } from 'next-auth/client'
|
||||
|
||||
export default function SignIn({ providers }) {
|
||||
const [email, setEmail] = useState('')
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.values(providers).map((provider) => {
|
||||
if (provider.id === 'workos') {
|
||||
return (
|
||||
<div key={provider.id}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
onChange={(event) => setEmail(event.target.value)}
|
||||
/>
|
||||
<button
|
||||
onClick={() =>
|
||||
signIn(provider.id, undefined, {
|
||||
domain: email.split('@')[1],
|
||||
})
|
||||
}
|
||||
>
|
||||
Sign in with SSO
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={provider.id}>
|
||||
<button onClick={() => signIn(provider.id)}>
|
||||
Sign in with {provider.name}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// This is the recommended way for Next.js 9.3 or newer
|
||||
export async function getServerSideProps(context){
|
||||
const providers = await getProviders()
|
||||
return {
|
||||
props: { providers }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// If older than Next.js 9.3
|
||||
SignIn.getInitialProps = async () => {
|
||||
return {
|
||||
providers: await getProviders()
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
@@ -5,7 +5,19 @@ title: Database Adapters
|
||||
|
||||
An **Adapter** in NextAuth.js connects your application to whatever database or backend system you want to use to store data for user accounts, sessions, etc.
|
||||
|
||||
You do not need to specify an Adapter explicitly unless you want to use advanced options such as custom models or schemas, if you want to use the Prisma Adapter instead of the default TypeORM Adapter, or if you are creating a custom Adapter to connect to a database that is not one of the supported databases.
|
||||
The adapters can be found in their own repository under [`nextauthjs/adapters`](https://github.com/nextauthjs/adapters).
|
||||
|
||||
There you can find the following adapters:
|
||||
|
||||
- typeorm-legacy
|
||||
- prisma
|
||||
- prisma-legacy
|
||||
- fauna
|
||||
- dynamodb
|
||||
|
||||
## TypeORM Adapter
|
||||
|
||||
NextAuth.js comes with a default Adapter that uses [TypeORM](https://typeorm.io/) so that it can be used with many different databases without any further configuration, you simply add the node module for the database driver you want to use in your project and pass a database connection string to NextAuth.js.
|
||||
|
||||
### Database Schemas
|
||||
|
||||
@@ -15,11 +27,7 @@ Configure your database by creating the tables and columns to match the schema e
|
||||
- [Postgres Schema](/schemas/postgres)
|
||||
- [Microsoft SQL Server Schema](/schemas/mssql)
|
||||
|
||||
## TypeORM Adapter
|
||||
|
||||
NextAuth.js comes with a default Adapter that uses [TypeORM](https://typeorm.io/) so that it can be used with many different databases without any further configuration, you simply add the node module for the database driver you want to use to your project and pass a database connection string to NextAuth.js.
|
||||
|
||||
The default Adapter is the TypeORM Adapter, the following configuration options are exactly equivalent.
|
||||
The default Adapter is the TypeORM Adapter and the default database type for TypeORM is SQLite, the following configuration options are exactly equivalent.
|
||||
|
||||
```javascript
|
||||
database: {
|
||||
@@ -48,9 +56,7 @@ adapter: Adapters.TypeORM.Adapter({
|
||||
The tutorial [Custom models with TypeORM](/tutorials/typeorm-custom-models) explains how to extend the built in models and schemas used by the TypeORM Adapter. You can use these models in your own code.
|
||||
|
||||
:::tip
|
||||
The `synchronize` option in TypeORM will generate SQL that exactly matches the documented schemas for MySQL and Postgres.
|
||||
|
||||
However, it should not be enabled against production databases as it may cause data loss if the configured schema does not match the expected schema!
|
||||
The `synchronize` option in TypeORM will generate SQL that exactly matches the documented schemas for MySQL and Postgres. This will automatically apply any changes it finds in the entity model, therefore it **should not be enabled against production databases** as it may cause data loss if the configured schema does not match the expected schema!
|
||||
:::
|
||||
|
||||
## Prisma Adapter
|
||||
|
||||
43
www/docs/schemas/fauna.md
Normal file
43
www/docs/schemas/fauna.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# FaunaDB
|
||||
|
||||
FaunaDB Schema (`@next-auth/fauna-adapter`)
|
||||
|
||||
## Setup
|
||||
|
||||
```javascript
|
||||
CreateCollection({ name: 'accounts' })
|
||||
CreateCollection({ name: 'sessions' })
|
||||
CreateCollection({ name: 'users' })
|
||||
CreateCollection({ name: 'verification_requests' })
|
||||
CreateIndex({
|
||||
name: 'account_by_provider_account_id',
|
||||
source: Collection('accounts'),
|
||||
unique: true,
|
||||
terms: [
|
||||
{ field: ['data', 'providerId'] },
|
||||
{ field: ['data', 'providerAccountId'] },
|
||||
],
|
||||
})
|
||||
CreateIndex({
|
||||
name: 'session_by_token',
|
||||
source: Collection('sessions'),
|
||||
unique: true,
|
||||
terms: [{ field: ['data', 'sessionToken'] }],
|
||||
})
|
||||
CreateIndex({
|
||||
name: 'user_by_email',
|
||||
source: Collection('users'),
|
||||
unique: true,
|
||||
terms: [{ field: ['data', 'email'] }],
|
||||
})
|
||||
CreateIndex({
|
||||
name: 'verification_request_by_token',
|
||||
source: Collection('verification_requests'),
|
||||
unique: true,
|
||||
terms: [
|
||||
{ field: ['data', 'token'] },
|
||||
{ field: ['data', 'identifier'] }
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
144
www/docs/schemas/prisma.md
Normal file
144
www/docs/schemas/prisma.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Prisma
|
||||
|
||||
Schema for the Prisma2 Adapter (`@next-auth/prisma-adapter`)
|
||||
|
||||
## Schema
|
||||
|
||||
```prisma filename="schema.prisma"
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
providerType String
|
||||
providerId String
|
||||
providerAccountId String
|
||||
refreshToken String?
|
||||
accessToken String?
|
||||
accessTokenExpires DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@unique([providerId, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
expires DateTime
|
||||
sessionToken String @unique
|
||||
accessToken String @unique
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
}
|
||||
|
||||
model VerificationRequest {
|
||||
id String @id @default(cuid())
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([identifier, token])
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Changes from the original Prisma Adapter
|
||||
|
||||
```diff
|
||||
model Account {
|
||||
- id Int @default(autoincrement()) @id
|
||||
+ id String @id @default(cuid())
|
||||
- compoundId String @unique @map(name: "compound_id")
|
||||
- userId Int @map(name: "user_id")
|
||||
+ userId String
|
||||
+ user User @relation(fields: [userId], references: [id])
|
||||
- providerType String @map(name: "provider_type")
|
||||
+ providerType String
|
||||
- providerId String @map(name: "provider_id")
|
||||
+ providerId String
|
||||
- providerAccountId String @map(name: "provider_account_id")
|
||||
+ providerAccountId String
|
||||
- refreshToken String? @map(name: "refresh_token")
|
||||
+ refreshToken String?
|
||||
- accessToken String? @map(name: "access_token")
|
||||
+ accessToken String?
|
||||
- accessTokenExpires DateTime? @map(name: "access_token_expires")
|
||||
+ accessTokenExpires DateTime?
|
||||
- createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
+ createdAt DateTime @default(now())
|
||||
- updatedAt DateTime @default(now()) @map(name: "updated_at")
|
||||
+ updatedAt DateTime @updatedAt
|
||||
|
||||
- @@index([providerAccountId], name: "providerAccountId")
|
||||
- @@index([providerId], name: "providerId")
|
||||
- @@index([userId], name: "userId")
|
||||
- @@map(name: "accounts")
|
||||
+ @@unique([providerId, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
- id Int @default(autoincrement()) @id
|
||||
+ id String @id @default(cuid())
|
||||
- userId Int @map(name: "user_id")
|
||||
+ userId String
|
||||
+ user User @relation(fields: [userId], references: [id])
|
||||
expires DateTime
|
||||
- sessionToken String @unique @map(name: "session_token")
|
||||
+ sessionToken String @unique
|
||||
- accessToken String @unique @map(name: "access_token")
|
||||
+ accessToken String @unique
|
||||
- createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
+ createdAt DateTime @default(now())
|
||||
- updatedAt DateTime @default(now()) @map(name: "updated_at")
|
||||
+ updatedAt DateTime @updatedAt
|
||||
-
|
||||
- @@map(name: "sessions")
|
||||
}
|
||||
|
||||
model User {
|
||||
- id Int @default(autoincrement()) @id
|
||||
+ id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
- emailVerified DateTime? @map(name: "email_verified")
|
||||
+ emailVerified DateTime?
|
||||
image String?
|
||||
+ accounts Account[]
|
||||
+ sessions Session[]
|
||||
- createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
+ createdAt DateTime @default(now())
|
||||
- updatedAt DateTime @default(now()) @map(name: "updated_at")
|
||||
+ updatedAt DateTime @updatedAt
|
||||
|
||||
- @@map(name: "users")
|
||||
}
|
||||
|
||||
model VerificationRequest {
|
||||
- id Int @default(autoincrement()) @id
|
||||
+ id String @id @default(cuid())
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
- createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
+ createdAt DateTime @default(now())
|
||||
- updatedAt DateTime @default(now()) @map(name: "updated_at")
|
||||
+ updatedAt DateTime @updatedAt
|
||||
|
||||
- @@map(name: "verification_requests")
|
||||
+ @@unique([identifier, token])
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export default NextAuth({
|
||||
username: { label: "DN", type: "text", placeholder: "" },
|
||||
password: { label: "Password", type: "password" },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
async authorize(credentials, req) {
|
||||
// You might want to pull this call out so we're not making a new LDAP client on every login attemp
|
||||
const client = ldap.createClient({
|
||||
url: process.env.LDAP_URI,
|
||||
|
||||
@@ -1,52 +1,57 @@
|
||||
module.exports = {
|
||||
title: 'NextAuth.js',
|
||||
tagline: 'Authentication for Next.js',
|
||||
url: 'https://next-auth.js.org',
|
||||
baseUrl: '/',
|
||||
favicon: 'img/favicon.ico',
|
||||
organizationName: 'nextauthjs',
|
||||
projectName: 'next-auth',
|
||||
title: "NextAuth.js",
|
||||
tagline: "Authentication for Next.js",
|
||||
url: "https://next-auth.js.org",
|
||||
baseUrl: "/",
|
||||
favicon: "img/favicon.ico",
|
||||
organizationName: "nextauthjs",
|
||||
projectName: "next-auth",
|
||||
themeConfig: {
|
||||
sidebarCollapsible: true,
|
||||
prism: {
|
||||
theme: require('prism-react-renderer/themes/vsDark')
|
||||
theme: require("prism-react-renderer/themes/vsDark"),
|
||||
},
|
||||
algolia: {
|
||||
apiKey: "b81e3ca39a920b7815e880aea49c00ec",
|
||||
indexName: "next-auth",
|
||||
searchParameters: {},
|
||||
},
|
||||
navbar: {
|
||||
title: 'NextAuth.js',
|
||||
title: "NextAuth.js",
|
||||
logo: {
|
||||
alt: 'NextAuth Logo',
|
||||
src: 'img/logo/logo-xs.png'
|
||||
alt: "NextAuth Logo",
|
||||
src: "img/logo/logo-xs.png",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
to: '/getting-started/introduction',
|
||||
activeBasePath: 'docs',
|
||||
label: 'Documentation',
|
||||
position: 'left'
|
||||
to: "/getting-started/introduction",
|
||||
activeBasePath: "docs",
|
||||
label: "Documentation",
|
||||
position: "left",
|
||||
},
|
||||
{
|
||||
to: '/tutorials',
|
||||
activeBasePath: 'docs',
|
||||
label: 'Tutorials',
|
||||
position: 'left'
|
||||
to: "/tutorials",
|
||||
activeBasePath: "docs",
|
||||
label: "Tutorials",
|
||||
position: "left",
|
||||
},
|
||||
{
|
||||
to: '/faq',
|
||||
activeBasePath: 'docs',
|
||||
label: 'FAQ',
|
||||
position: 'left'
|
||||
to: "/faq",
|
||||
activeBasePath: "docs",
|
||||
label: "FAQ",
|
||||
position: "left",
|
||||
},
|
||||
{
|
||||
href: 'https://www.npmjs.com/package/next-auth',
|
||||
label: 'npm',
|
||||
position: 'right'
|
||||
href: "https://www.npmjs.com/package/next-auth",
|
||||
label: "npm",
|
||||
position: "right",
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/nextauthjs/next-auth',
|
||||
label: 'GitHub',
|
||||
position: 'right'
|
||||
}
|
||||
]
|
||||
href: "https://github.com/nextauthjs/next-auth",
|
||||
label: "GitHub",
|
||||
position: "right",
|
||||
},
|
||||
],
|
||||
},
|
||||
// announcementBar: {
|
||||
// id: 'release-candiate-announcement',
|
||||
@@ -57,45 +62,45 @@ module.exports = {
|
||||
footer: {
|
||||
links: [
|
||||
{
|
||||
title: 'About NextAuth.js',
|
||||
title: "About NextAuth.js",
|
||||
items: [
|
||||
{
|
||||
label: 'Introduction',
|
||||
to: '/getting-started/introduction'
|
||||
label: "Introduction",
|
||||
to: "/getting-started/introduction",
|
||||
},
|
||||
{
|
||||
label: 'Contributors',
|
||||
to: '/contributors'
|
||||
label: "Contributors",
|
||||
to: "/contributors",
|
||||
},
|
||||
{
|
||||
label: 'Canary documentation',
|
||||
to: 'https://next-auth-git-canary.nextauthjs.vercel.app/'
|
||||
}
|
||||
]
|
||||
label: "Canary documentation",
|
||||
to: "https://next-auth-git-canary.nextauthjs.vercel.app/",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Download',
|
||||
title: "Download",
|
||||
items: [
|
||||
{
|
||||
label: 'GitHub',
|
||||
to: 'https://github.com/nextauthjs/next-auth'
|
||||
label: "GitHub",
|
||||
to: "https://github.com/nextauthjs/next-auth",
|
||||
},
|
||||
{
|
||||
label: 'NPM',
|
||||
to: 'https://www.npmjs.com/package/next-auth'
|
||||
}
|
||||
]
|
||||
label: "NPM",
|
||||
to: "https://www.npmjs.com/package/next-auth",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Acknowledgements',
|
||||
title: "Acknowledgements",
|
||||
items: [
|
||||
{
|
||||
label: 'Docusaurus',
|
||||
to: 'https://v2.docusaurus.io/'
|
||||
label: "Docusaurus",
|
||||
to: "https://v2.docusaurus.io/",
|
||||
},
|
||||
{
|
||||
label: 'Images by unDraw',
|
||||
to: 'https://undraw.co/'
|
||||
label: "Images by unDraw",
|
||||
to: "https://undraw.co/",
|
||||
},
|
||||
{
|
||||
html: `
|
||||
@@ -106,28 +111,27 @@ module.exports = {
|
||||
height="32"
|
||||
src="https://raw.githubusercontent.com/nextauthjs/next-auth/canary/www/static/img/powered-by-vercel.svg"
|
||||
/>
|
||||
</a>`
|
||||
}
|
||||
]
|
||||
}
|
||||
</a>`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
copyright: 'NextAuth.js © Iain Collins 2021'
|
||||
}
|
||||
copyright: "NextAuth.js © Iain Collins 2021",
|
||||
},
|
||||
},
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
"@docusaurus/preset-classic",
|
||||
{
|
||||
docs: {
|
||||
routeBasePath: '/',
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl: 'https://github.com/nextauthjs/next-auth/edit/main/www'
|
||||
routeBasePath: "/",
|
||||
sidebarPath: require.resolve("./sidebars.js"),
|
||||
editUrl: "https://github.com/nextauthjs/next-auth/edit/main/www",
|
||||
},
|
||||
theme: {
|
||||
customCss: require.resolve('./src/css/index.css')
|
||||
}
|
||||
}
|
||||
]
|
||||
customCss: require.resolve("./src/css/index.css"),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: ['docusaurus-lunr-search']
|
||||
}
|
||||
|
||||
606
www/package-lock.json
generated
606
www/package-lock.json
generated
@@ -11,8 +11,6 @@
|
||||
"@docusaurus/core": "2.0.0-beta.0",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.0",
|
||||
"classnames": "^2.3.1",
|
||||
"docusaurus-lunr-search": "^2.1.14",
|
||||
"jose": "^2.0.5",
|
||||
"lodash.times": "^4.3.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
@@ -2188,14 +2186,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@panva/asn1.js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz",
|
||||
"integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
"version": "1.0.0-next.12",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz",
|
||||
@@ -2787,11 +2777,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
@@ -3005,11 +2990,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.0.tgz",
|
||||
@@ -3180,14 +3160,6 @@
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/autocomplete.js": {
|
||||
"version": "0.37.1",
|
||||
"resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz",
|
||||
"integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==",
|
||||
"dependencies": {
|
||||
"immediate": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz",
|
||||
@@ -3453,11 +3425,6 @@
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
"integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
|
||||
},
|
||||
"node_modules/bcp-47-match": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz",
|
||||
"integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w=="
|
||||
},
|
||||
"node_modules/big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
@@ -4163,14 +4130,6 @@
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"bin": {
|
||||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
|
||||
@@ -4290,11 +4249,6 @@
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"node_modules/contains-path": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
|
||||
@@ -4584,11 +4538,6 @@
|
||||
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
|
||||
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
|
||||
},
|
||||
"node_modules/css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g=="
|
||||
},
|
||||
"node_modules/css-to-react-native": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz",
|
||||
@@ -4976,14 +4925,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==",
|
||||
"bin": {
|
||||
"direction": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
@@ -5018,39 +4959,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/docusaurus-lunr-search": {
|
||||
"version": "2.1.14",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.1.14.tgz",
|
||||
"integrity": "sha512-cL1TBFQPZ8/NNBrC8N3JeE5uJD1hpKPWHaU7NyndJqFhwOGK7L9FFnl5vc7LPiCOLvuYlw3Xu26/of9/IEC6VA==",
|
||||
"dependencies": {
|
||||
"autocomplete.js": "^0.37.0",
|
||||
"classnames": "^2.2.6",
|
||||
"gauge": "^3.0.0",
|
||||
"hast-util-select": "^4.0.0",
|
||||
"hast-util-to-text": "^2.0.0",
|
||||
"hogan.js": "^3.0.2",
|
||||
"lunr": "^2.3.8",
|
||||
"lunr-languages": "^1.4.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"rehype-parse": "^7.0.1",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.0.0",
|
||||
"unist-util-is": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/docusaurus-lunr-search/node_modules/rehype-parse": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz",
|
||||
"integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==",
|
||||
"dependencies": {
|
||||
"hast-util-from-parse5": "^6.0.0",
|
||||
"parse5": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-converter": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
||||
@@ -6690,55 +6598,6 @@
|
||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.0.tgz",
|
||||
"integrity": "sha512-VSxauaaCsLOTerAyzunAYGgK3iaWZvOL1BCvBvf/IhDWrczPAf1tUqn05DOCJOOe4k3vOdX6fHhJIvF2UtCMhw==",
|
||||
"dependencies": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^1.0.1 || ^2.0.0",
|
||||
"strip-ansi": "^3.0.1 || ^4.0.0",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge/node_modules/ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge/node_modules/string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dependencies": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge/node_modules/strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -7019,11 +6878,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
||||
},
|
||||
"node_modules/has-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
|
||||
@@ -7121,16 +6975,6 @@
|
||||
"web-namespaces": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-has-property": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
|
||||
"integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg=="
|
||||
},
|
||||
"node_modules/hast-util-is-element": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
|
||||
"integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ=="
|
||||
},
|
||||
"node_modules/hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
@@ -7157,27 +7001,6 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-select": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz",
|
||||
"integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==",
|
||||
"dependencies": {
|
||||
"bcp-47-match": "^1.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"css-selector-parser": "^1.0.0",
|
||||
"direction": "^1.0.0",
|
||||
"hast-util-has-property": "^1.0.0",
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"hast-util-to-string": "^1.0.0",
|
||||
"hast-util-whitespace": "^1.0.0",
|
||||
"not": "^0.1.0",
|
||||
"nth-check": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0",
|
||||
"unist-util-visit": "^2.0.0",
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-parse5": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
|
||||
@@ -7194,26 +7017,6 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-string": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz",
|
||||
"integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w=="
|
||||
},
|
||||
"node_modules/hast-util-to-text": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz",
|
||||
"integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==",
|
||||
"dependencies": {
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"repeat-string": "^1.0.0",
|
||||
"unist-util-find-after": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-whitespace": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
|
||||
"integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A=="
|
||||
},
|
||||
"node_modules/hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
@@ -7252,26 +7055,6 @@
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hogan.js": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
||||
"integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=",
|
||||
"dependencies": {
|
||||
"mkdirp": "0.3.0",
|
||||
"nopt": "1.0.10"
|
||||
},
|
||||
"bin": {
|
||||
"hulk": "bin/hulk"
|
||||
}
|
||||
},
|
||||
"node_modules/hogan.js/node_modules/mkdirp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
||||
"integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -7726,11 +7509,6 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz",
|
||||
@@ -8478,17 +8256,6 @@
|
||||
"@sideway/pinpoint": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz",
|
||||
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==",
|
||||
"dependencies": {
|
||||
"@panva/asn1.js": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0 < 13 || >=13.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -8872,16 +8639,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
|
||||
},
|
||||
"node_modules/lunr-languages": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.4.0.tgz",
|
||||
"integrity": "sha512-YWfZDExJN/MJEVE/DbM4AuVRLsqeHi+q3wmECMsWjGIOkd5mr9DUNos7fv8f5do9VLRMYXIzFjn+N4+KPI9pQA=="
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@@ -9363,17 +9120,6 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz",
|
||||
"integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg=="
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
||||
@@ -9419,11 +9165,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/not": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
|
||||
"integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0="
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
@@ -13475,23 +13216,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-vfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
|
||||
"integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
|
||||
"dependencies": {
|
||||
"is-buffer": "^2.0.0",
|
||||
"vfile": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-vfile/node_modules/is-buffer": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||
@@ -13744,14 +13468,6 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-find-after": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz",
|
||||
"integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==",
|
||||
"dependencies": {
|
||||
"unist-util-is": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-generated": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz",
|
||||
@@ -14850,45 +14566,6 @@
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"dependencies": {
|
||||
"string-width": "^1.0.2 || 2"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align/node_modules/ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align/node_modules/string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dependencies": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align/node_modules/strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/widest-line": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
|
||||
@@ -17132,11 +16809,6 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@panva/asn1.js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz",
|
||||
"integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw=="
|
||||
},
|
||||
"@polka/url": {
|
||||
"version": "1.0.0-next.12",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz",
|
||||
@@ -17663,11 +17335,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
@@ -17836,11 +17503,6 @@
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
|
||||
},
|
||||
"arg": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.0.tgz",
|
||||
@@ -17969,14 +17631,6 @@
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||
},
|
||||
"autocomplete.js": {
|
||||
"version": "0.37.1",
|
||||
"resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.37.1.tgz",
|
||||
"integrity": "sha512-PgSe9fHYhZEsm/9jggbjtVsGXJkPLvd+9mC7gZJ662vVL5CRWEtm/mIrrzCx0MrNxHVwxD5d00UOn6NsmL2LUQ==",
|
||||
"requires": {
|
||||
"immediate": "^3.2.3"
|
||||
}
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz",
|
||||
@@ -18198,11 +17852,6 @@
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
"integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
|
||||
},
|
||||
"bcp-47-match": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-1.0.3.tgz",
|
||||
"integrity": "sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w=="
|
||||
},
|
||||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
@@ -18793,11 +18442,6 @@
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
|
||||
},
|
||||
"colorette": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
|
||||
@@ -18898,11 +18542,6 @@
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
|
||||
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw=="
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"contains-path": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
|
||||
@@ -19132,11 +18771,6 @@
|
||||
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
|
||||
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
|
||||
},
|
||||
"css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
"integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g=="
|
||||
},
|
||||
"css-to-react-native": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz",
|
||||
@@ -19441,11 +19075,6 @@
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ=="
|
||||
},
|
||||
"dns-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||
@@ -19477,38 +19106,6 @@
|
||||
"esutils": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"docusaurus-lunr-search": {
|
||||
"version": "2.1.14",
|
||||
"resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-2.1.14.tgz",
|
||||
"integrity": "sha512-cL1TBFQPZ8/NNBrC8N3JeE5uJD1hpKPWHaU7NyndJqFhwOGK7L9FFnl5vc7LPiCOLvuYlw3Xu26/of9/IEC6VA==",
|
||||
"requires": {
|
||||
"autocomplete.js": "^0.37.0",
|
||||
"classnames": "^2.2.6",
|
||||
"gauge": "^3.0.0",
|
||||
"hast-util-select": "^4.0.0",
|
||||
"hast-util-to-text": "^2.0.0",
|
||||
"hogan.js": "^3.0.2",
|
||||
"lunr": "^2.3.8",
|
||||
"lunr-languages": "^1.4.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"rehype-parse": "^7.0.1",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.0.0",
|
||||
"unist-util-is": "^4.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"rehype-parse": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-7.0.1.tgz",
|
||||
"integrity": "sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==",
|
||||
"requires": {
|
||||
"hast-util-from-parse5": "^6.0.0",
|
||||
"parse5": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dom-converter": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
||||
@@ -20852,45 +20449,6 @@
|
||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
||||
"dev": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.0.tgz",
|
||||
"integrity": "sha512-VSxauaaCsLOTerAyzunAYGgK3iaWZvOL1BCvBvf/IhDWrczPAf1tUqn05DOCJOOe4k3vOdX6fHhJIvF2UtCMhw==",
|
||||
"requires": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^1.0.1 || ^2.0.0",
|
||||
"strip-ansi": "^3.0.1 || ^4.0.0",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -21117,11 +20675,6 @@
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
||||
},
|
||||
"has-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
|
||||
@@ -21201,16 +20754,6 @@
|
||||
"web-namespaces": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-has-property": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
|
||||
"integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg=="
|
||||
},
|
||||
"hast-util-is-element": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
|
||||
"integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ=="
|
||||
},
|
||||
"hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
@@ -21233,27 +20776,6 @@
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-select": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-4.0.2.tgz",
|
||||
"integrity": "sha512-8EEG2//bN5rrzboPWD2HdS3ugLijNioS1pqOTIolXNf67xxShYw4SQEmVXd3imiBG+U2bC2nVTySr/iRAA7Cjg==",
|
||||
"requires": {
|
||||
"bcp-47-match": "^1.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"css-selector-parser": "^1.0.0",
|
||||
"direction": "^1.0.0",
|
||||
"hast-util-has-property": "^1.0.0",
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"hast-util-to-string": "^1.0.0",
|
||||
"hast-util-whitespace": "^1.0.0",
|
||||
"not": "^0.1.0",
|
||||
"nth-check": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0",
|
||||
"unist-util-visit": "^2.0.0",
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-parse5": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
|
||||
@@ -21266,26 +20788,6 @@
|
||||
"zwitch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-to-string": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-1.0.4.tgz",
|
||||
"integrity": "sha512-eK0MxRX47AV2eZ+Lyr18DCpQgodvaS3fAQO2+b9Two9F5HEoRPhiUMNzoXArMJfZi2yieFzUBMRl3HNJ3Jus3w=="
|
||||
},
|
||||
"hast-util-to-text": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz",
|
||||
"integrity": "sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==",
|
||||
"requires": {
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
"repeat-string": "^1.0.0",
|
||||
"unist-util-find-after": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"hast-util-whitespace": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
|
||||
"integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A=="
|
||||
},
|
||||
"hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
@@ -21321,22 +20823,6 @@
|
||||
"value-equal": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hogan.js": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
|
||||
"integrity": "sha1-TNnhq9QpQUbnZ55B14mHMrAse/0=",
|
||||
"requires": {
|
||||
"mkdirp": "0.3.0",
|
||||
"nopt": "1.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
||||
"integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@@ -21731,11 +21217,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
|
||||
},
|
||||
"immer": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz",
|
||||
@@ -22292,14 +21773,6 @@
|
||||
"@sideway/pinpoint": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"jose": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz",
|
||||
"integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==",
|
||||
"requires": {
|
||||
"@panva/asn1.js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -22619,16 +22092,6 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
|
||||
},
|
||||
"lunr-languages": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.4.0.tgz",
|
||||
"integrity": "sha512-YWfZDExJN/MJEVE/DbM4AuVRLsqeHi+q3wmECMsWjGIOkd5mr9DUNos7fv8f5do9VLRMYXIzFjn+N4+KPI9pQA=="
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@@ -23013,14 +22476,6 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz",
|
||||
"integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg=="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
||||
@@ -23056,11 +22511,6 @@
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
|
||||
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ=="
|
||||
},
|
||||
"not": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
|
||||
"integrity": "sha1-yWkcF0bFXc++VMvYvU/wQbwrUZ0="
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
@@ -26314,22 +25764,6 @@
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"to-vfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
|
||||
"integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
|
||||
"requires": {
|
||||
"is-buffer": "^2.0.0",
|
||||
"vfile": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-buffer": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||
@@ -26522,14 +25956,6 @@
|
||||
"resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz",
|
||||
"integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw=="
|
||||
},
|
||||
"unist-util-find-after": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz",
|
||||
"integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==",
|
||||
"requires": {
|
||||
"unist-util-is": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"unist-util-generated": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz",
|
||||
@@ -27416,38 +26842,6 @@
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"requires": {
|
||||
"string-width": "^1.0.2 || 2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widest-line": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth-docs",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.0",
|
||||
"scripts": {
|
||||
"start": "npm run generate-providers && docusaurus start",
|
||||
"build": "npm run generate-providers && docusaurus build",
|
||||
@@ -17,8 +17,6 @@
|
||||
"@docusaurus/core": "2.0.0-beta.0",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.0",
|
||||
"classnames": "^2.3.1",
|
||||
"docusaurus-lunr-search": "^2.1.14",
|
||||
"jose": "^2.0.5",
|
||||
"lodash.times": "^4.3.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
@@ -1,31 +1,53 @@
|
||||
const providers = require('./providers.json')
|
||||
module.exports = {
|
||||
sidebar: {
|
||||
'Getting Started': [
|
||||
'getting-started/introduction',
|
||||
'getting-started/example',
|
||||
'getting-started/client',
|
||||
'getting-started/rest-api',
|
||||
'getting-started/typescript'
|
||||
],
|
||||
Configuration: [
|
||||
'configuration/options',
|
||||
'configuration/providers',
|
||||
'configuration/databases',
|
||||
'configuration/pages',
|
||||
'configuration/callbacks',
|
||||
'configuration/events'
|
||||
],
|
||||
'Models & Schemas': [
|
||||
'schemas/models',
|
||||
'schemas/mysql',
|
||||
'schemas/postgres',
|
||||
'schemas/mssql',
|
||||
'schemas/mongodb',
|
||||
'schemas/adapters'
|
||||
],
|
||||
'Authentication Providers': Object.entries(providers)
|
||||
.sort(([, a], [, b]) => a.localeCompare(b))
|
||||
.map(([provider]) => `providers/${provider}`)
|
||||
}
|
||||
docs: [
|
||||
{
|
||||
type: "category",
|
||||
label: "Getting Started",
|
||||
collapsed: false,
|
||||
items: [
|
||||
"getting-started/introduction",
|
||||
"getting-started/example",
|
||||
"getting-started/client",
|
||||
"getting-started/rest-api",
|
||||
"getting-started/typescript",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Configuration",
|
||||
collapsed: true,
|
||||
items: [
|
||||
"configuration/options",
|
||||
"configuration/providers",
|
||||
"configuration/databases",
|
||||
"configuration/pages",
|
||||
"configuration/callbacks",
|
||||
"configuration/events",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Models & Schemas",
|
||||
collapsed: true,
|
||||
items: [
|
||||
"schemas/models",
|
||||
"schemas/mysql",
|
||||
"schemas/postgres",
|
||||
"schemas/mssql",
|
||||
"schemas/mongodb",
|
||||
"schemas/adapters",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Authentication Providers",
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "providers",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ html[data-theme="dark"]:root {
|
||||
@import "table-of-contents.css";
|
||||
@import "sidebar.css";
|
||||
@import "providers.css";
|
||||
@import "search.css";
|
||||
|
||||
@media screen and (max-width: 360px) {
|
||||
html {
|
||||
@@ -183,9 +184,26 @@ html[data-theme="dark"] hr {
|
||||
border-color: #242526;
|
||||
}
|
||||
|
||||
.github-counter {
|
||||
position: absolute;
|
||||
color: #000;
|
||||
top: -10px;
|
||||
right: 5px;
|
||||
font-size: 9px;
|
||||
background-color: #ccc;
|
||||
padding: 2px 5px;
|
||||
border-radius: 10px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .github-counter {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.navbar__item.navbar__link[href*="github"],
|
||||
.navbar__item.navbar__link[href*="npmjs"] {
|
||||
padding: 0 1rem 0 0;
|
||||
padding: 0 1.5rem 0 0;
|
||||
display: flex;
|
||||
font-size: 0;
|
||||
}
|
||||
@@ -199,7 +217,12 @@ html[data-theme="dark"] hr {
|
||||
}
|
||||
|
||||
.navbar__items .react-toggle {
|
||||
margin-right: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.react-toggle--focus .react-toggle-thumb,
|
||||
.react-toggle:hover .react-toggle-thumb {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.navbar__search-input:focus {
|
||||
|
||||
28
www/src/css/search.css
Normal file
28
www/src/css/search.css
Normal file
@@ -0,0 +1,28 @@
|
||||
html[data-theme="light"]:root {
|
||||
--docsearch-searchbox-shadow: inset 0 0 0 2px #a553b3;
|
||||
}
|
||||
|
||||
html[data-theme="light"] .DocSearch-Modal .DocSearch-Search-Icon {
|
||||
color: #a553b3;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .DocSearch-Modal .DocSearch-Search-Icon {
|
||||
color: #7c2f89;
|
||||
}
|
||||
|
||||
html[data-theme="dark"]:root {
|
||||
--docsearch-searchbox-background: #040404;
|
||||
--docsearch-key-gradient: #000;
|
||||
--docsearch-key-shadow: #ccc;
|
||||
--docsearch-searchbox-shadow: inset 0 0 0 2px #7c2f89;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .DocSearch-Button-Key {
|
||||
--docsearch-muted-color: #333;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 740px) {
|
||||
.DocSearch-Container {
|
||||
margin-top: 60px;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,50 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import Layout from '@theme/Layout'
|
||||
import Link from '@docusaurus/Link'
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||
import CodeBlock from '@theme/CodeBlock'
|
||||
import ProviderMarquee from '../components/ProviderMarquee'
|
||||
import Seo from './seo'
|
||||
import styles from './index.module.css'
|
||||
import React, { useEffect } from "react"
|
||||
import classnames from "classnames"
|
||||
import Layout from "@theme/Layout"
|
||||
import Link from "@docusaurus/Link"
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl"
|
||||
import CodeBlock from "@theme/CodeBlock"
|
||||
import ProviderMarquee from "../components/ProviderMarquee"
|
||||
import Seo from "./seo"
|
||||
import styles from "./index.module.css"
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: 'Easy',
|
||||
imageUrl: 'img/undraw_social.svg',
|
||||
title: "Easy",
|
||||
imageUrl: "img/undraw_social.svg",
|
||||
description: (
|
||||
<ul>
|
||||
<li>Built in support for popular services<br />
|
||||
<li>
|
||||
Built in support for popular services
|
||||
<br />
|
||||
<em>(Google, Facebook, Auth0, Apple…)</em>
|
||||
</li>
|
||||
<li>Built in email / passwordless / magic link</li>
|
||||
<li>Use with any username / password store</li>
|
||||
<li>Use with OAuth 1.0 & 2.0 services</li>
|
||||
</ul>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Flexible',
|
||||
imageUrl: 'img/undraw_authentication.svg',
|
||||
title: "Flexible",
|
||||
imageUrl: "img/undraw_authentication.svg",
|
||||
description: (
|
||||
<ul>
|
||||
<li>Built for Serverless, runs anywhere</li>
|
||||
<li>
|
||||
Bring Your Own Database - or none!<br />
|
||||
Bring Your Own Database - or none!
|
||||
<br />
|
||||
<em>(MySQL, Postgres, MSSQL, MongoDB…)</em>
|
||||
</li>
|
||||
<li>Choose database sessions or JWT</li>
|
||||
<li>Secure web pages and API routes</li>
|
||||
</ul>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Secure',
|
||||
imageUrl: 'img/undraw_secure.svg',
|
||||
title: "Secure",
|
||||
imageUrl: "img/undraw_secure.svg",
|
||||
description: (
|
||||
<ul>
|
||||
<li>Signed, prefixed, server-only cookies</li>
|
||||
@@ -50,84 +53,105 @@ const features = [
|
||||
<li>Tab syncing, auto-revalidation, keepalives</li>
|
||||
<li>Doesn't rely on client side JavaScript</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
function Feature ({ imageUrl, title, description }) {
|
||||
const kFormatter = (num) => {
|
||||
return Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k"
|
||||
}
|
||||
|
||||
function Feature({ imageUrl, title, description }) {
|
||||
const imgUrl = useBaseUrl(imageUrl)
|
||||
return (
|
||||
<div className={classnames('col col--4', styles.feature)}>
|
||||
<div className={classnames("col col--4", styles.feature)}>
|
||||
{imgUrl && (
|
||||
<div className='text--center'>
|
||||
<div className='feature-image-wrapper'>
|
||||
<div className="text--center">
|
||||
<div className="feature-image-wrapper">
|
||||
<img className={styles.featureImage} src={imgUrl} alt={title} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<h3 className='text--center'>{title}</h3>
|
||||
<h3 className="text--center">{title}</h3>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Home () {
|
||||
function Home() {
|
||||
const context = useDocusaurusContext()
|
||||
const { siteConfig = {} } = context
|
||||
|
||||
useEffect(() => {
|
||||
fetch("https://api.github.com/repos/nextauthjs/next-auth")
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const navLinks = document.getElementsByClassName(
|
||||
"navbar__item navbar__link"
|
||||
)
|
||||
const githubStat = document.createElement("span")
|
||||
githubStat.innerHTML = kFormatter(data.stargazers_count)
|
||||
githubStat.className = "github-counter"
|
||||
navLinks[4].appendChild(githubStat)
|
||||
})
|
||||
}, [])
|
||||
return (
|
||||
<Layout description={siteConfig.tagline}>
|
||||
<Seo />
|
||||
<div className='home-wrapper'>
|
||||
<header className={classnames('hero', styles.heroBanner)}>
|
||||
<div className='container'>
|
||||
<div className='hero-inner'>
|
||||
<div className="home-wrapper">
|
||||
<header className={classnames("hero", styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<div className="hero-inner">
|
||||
<img
|
||||
src='/img/logo/logo-sm.png'
|
||||
alt='Shield with key icon'
|
||||
src="/img/logo/logo-sm.png"
|
||||
alt="Shield with key icon"
|
||||
className={styles.heroLogo}
|
||||
/>
|
||||
<div className={styles.heroText}>
|
||||
<h1 className='hero__title'>{siteConfig.title}</h1>
|
||||
<p className='hero__subtitle'>{siteConfig.tagline}</p>
|
||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
</div>
|
||||
<div className={styles.buttons}>
|
||||
<a
|
||||
className={classnames(
|
||||
'button button--outline button--secondary button--lg rounded-pill',
|
||||
"button button--outline button--secondary button--lg rounded-pill",
|
||||
styles.button
|
||||
)}
|
||||
href='https://next-auth-example.now.sh'
|
||||
>Live Demo
|
||||
href="https://next-auth-example.now.sh"
|
||||
>
|
||||
Live Demo
|
||||
</a>
|
||||
<Link
|
||||
className={classnames(
|
||||
'button button--primary button--lg rounded-pill',
|
||||
"button button--primary button--lg rounded-pill",
|
||||
styles.button
|
||||
)}
|
||||
to={useBaseUrl('/getting-started/example')}
|
||||
>Get Started
|
||||
to={useBaseUrl("/getting-started/example")}
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='hero-marquee'>
|
||||
<div className="hero-marquee">
|
||||
<ProviderMarquee />
|
||||
</div>
|
||||
</div>
|
||||
<div className='hero-wave'>
|
||||
<div className='hero-wave-inner' />
|
||||
<div className="hero-wave">
|
||||
<div className="hero-wave-inner" />
|
||||
</div>
|
||||
</header>
|
||||
<main className='home-main'>
|
||||
<main className="home-main">
|
||||
<section className={`section-features ${styles.features}`}>
|
||||
<div className='container'>
|
||||
<div className='row'>
|
||||
<div className='col'>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<h2 className={styles.featuresTitle}>
|
||||
<span>Open Source.</span> <span>Full Stack.</span> <span>Own Your Data.</span>
|
||||
<span>Open Source.</span> <span>Full Stack.</span>{" "}
|
||||
<span>Own Your Data.</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className="row">
|
||||
{features.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
@@ -135,53 +159,63 @@ function Home () {
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div className='container'>
|
||||
<div className='row'>
|
||||
<div className='col'>
|
||||
<p className='text--center'>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<p className="text--center">
|
||||
<a
|
||||
href='https://www.npmjs.com/package/next-auth'
|
||||
className='button button--primary button--outline rounded-pill button--lg'
|
||||
>npm install next-auth
|
||||
href="https://www.npmjs.com/package/next-auth"
|
||||
className="button button--primary button--outline rounded-pill button--lg"
|
||||
>
|
||||
npm install next-auth
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col'>
|
||||
<h2 className='text--center' style={{ fontSize: '2.5rem' }}>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<h2 className="text--center" style={{ fontSize: "2.5rem" }}>
|
||||
Add authentication in minutes!
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col col--6'>
|
||||
<div className='code'>
|
||||
<h4 className='code-heading'>Server <span>/pages/api/auth/[...nextauth].js</span></h4>
|
||||
<CodeBlock className='javascript'>{serverlessFunctionCode}</CodeBlock>
|
||||
<div className="row">
|
||||
<div className="col col--6">
|
||||
<div className="code">
|
||||
<h4 className="code-heading">
|
||||
Server <span>/pages/api/auth/[...nextauth].js</span>
|
||||
</h4>
|
||||
<CodeBlock className="javascript">
|
||||
{serverlessFunctionCode}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col col--6'>
|
||||
<div className='code'>
|
||||
<h4 className='code-heading'>Client <span>/pages/index.js</span></h4>
|
||||
<CodeBlock className='javascript'>{reactComponentCode}</CodeBlock>
|
||||
<div className="col col--6">
|
||||
<div className="code">
|
||||
<h4 className="code-heading">
|
||||
Client <span>/pages/index.js</span>
|
||||
</h4>
|
||||
<CodeBlock className="javascript">
|
||||
{reactComponentCode}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col'>
|
||||
<p className='text--center' style={{ marginTop: '2rem' }}>
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<p className="text--center" style={{ marginTop: "2rem" }}>
|
||||
<Link
|
||||
to='/getting-started/example'
|
||||
className='button button--primary button--lg rounded-pill'
|
||||
>Example Code
|
||||
to="/getting-started/example"
|
||||
className="button button--primary button--lg rounded-pill"
|
||||
>
|
||||
Example Code
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div className='home-subtitle'>
|
||||
<div className="home-subtitle">
|
||||
<p>NextAuth.js is an open source community project.</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
}
|
||||
|
||||
.heroLogo {
|
||||
margin-bottom: .5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
width: 8rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 689px) {
|
||||
.heroLogo {
|
||||
margin-bottom: -.5rem;
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@
|
||||
}
|
||||
|
||||
.features ul li {
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1rem;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
@@ -102,4 +102,4 @@
|
||||
.featureImage {
|
||||
height: 220px;
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
import React from 'react'
|
||||
import Head from '@docusaurus/Head'
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
|
||||
import React from "react"
|
||||
import Head from "@docusaurus/Head"
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
|
||||
|
||||
const Seo = () => {
|
||||
const context = useDocusaurusContext()
|
||||
const { siteConfig = {} } = context
|
||||
const {
|
||||
title,
|
||||
tagline,
|
||||
url
|
||||
} = siteConfig
|
||||
const { title, tagline, url } = siteConfig
|
||||
|
||||
return (
|
||||
<Head>
|
||||
<meta charSet='utf-8' />
|
||||
<link rel='canonical' href={url} />
|
||||
<meta property='og:title' content={title} />
|
||||
<meta property='og:description' content={tagline} />
|
||||
<meta property='og:image' content={`${url}/img/social-media-card.png`} />
|
||||
<meta property='og:url' content={url} />
|
||||
<meta name='twitter:card' content='summary_large_image' />
|
||||
<meta name='twitter:title' content={title} />
|
||||
<meta name='twitter:description' content={tagline} />
|
||||
<meta name='twitter:image' content={`${url}/img/social-media-card.png`} />
|
||||
<meta charSet="utf-8" />
|
||||
<link rel="canonical" href={url} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={tagline} />
|
||||
<meta property="og:image" content={`${url}/img/social-media-card.png`} />
|
||||
<meta property="og:url" content={url} />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={tagline} />
|
||||
<meta name="twitter:image" content={`${url}/img/social-media-card.png`} />
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,141 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React, { useRef, useCallback, useEffect } from "react"
|
||||
import classnames from "classnames"
|
||||
import { useHistory } from "@docusaurus/router"
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
|
||||
import "./styles.css"
|
||||
|
||||
let loaded = false
|
||||
const Search = (props) => {
|
||||
const initialized = useRef(false)
|
||||
const searchBarRef = useRef(null)
|
||||
const history = useHistory()
|
||||
const { siteConfig = {} } = useDocusaurusContext()
|
||||
const { baseUrl } = siteConfig
|
||||
const initAlgolia = () => {
|
||||
if (!initialized.current) {
|
||||
new window.DocSearch({
|
||||
searchData: window.searchData,
|
||||
inputSelector: "#search_input_react",
|
||||
// Override algolia's default selection event, allowing us to do client-side
|
||||
// navigation and avoiding a full page refresh.
|
||||
handleSelected: (_input, _event, suggestion) => {
|
||||
const url = baseUrl + suggestion.url
|
||||
// Use an anchor tag to parse the absolute url into a relative url
|
||||
// Alternatively, we can use new URL(suggestion.url) but its not supported in IE
|
||||
const a = document.createElement("a")
|
||||
a.href = url
|
||||
// Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id
|
||||
// So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details.
|
||||
|
||||
history.push(url)
|
||||
},
|
||||
})
|
||||
initialized.current = true
|
||||
}
|
||||
}
|
||||
|
||||
const getSearchData = () =>
|
||||
process.env.NODE_ENV === "production"
|
||||
? fetch(`${baseUrl}search-doc.json`).then((content) => content.json())
|
||||
: Promise.resolve([])
|
||||
|
||||
const loadAlgolia = () => {
|
||||
if (!loaded) {
|
||||
Promise.all([
|
||||
getSearchData(),
|
||||
import("./lib/DocSearch"),
|
||||
import("./algolia.css"),
|
||||
]).then(([searchData, { default: DocSearch }]) => {
|
||||
loaded = true
|
||||
window.searchData = searchData
|
||||
window.DocSearch = DocSearch
|
||||
initAlgolia()
|
||||
})
|
||||
} else {
|
||||
initAlgolia()
|
||||
}
|
||||
}
|
||||
|
||||
const toggleSearchIconClick = useCallback(
|
||||
(e) => {
|
||||
if (!searchBarRef.current.contains(e.target)) {
|
||||
searchBarRef.current.focus()
|
||||
}
|
||||
|
||||
props.handleSearchBarToggle &&
|
||||
props.handleSearchBarToggle(!props.isSearchBarExpanded)
|
||||
},
|
||||
[props.isSearchBarExpanded]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("keypress", (e) => {
|
||||
if (document.activeElement === searchBarRef.current) return
|
||||
if (e.key === "/") {
|
||||
e.preventDefault()
|
||||
searchBarRef.current.focus()
|
||||
}
|
||||
})
|
||||
return () => document.removeEventListener("keypress")
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="navbar__search" key="search-box">
|
||||
<span
|
||||
aria-label="expand searchbar"
|
||||
role="button"
|
||||
className={classnames("search-icon", {
|
||||
"search-icon-hidden": props.isSearchBarExpanded,
|
||||
})}
|
||||
onClick={toggleSearchIconClick}
|
||||
onKeyDown={toggleSearchIconClick}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<input
|
||||
id="search_input_react"
|
||||
type="search"
|
||||
placeholder="Search"
|
||||
aria-label="Search"
|
||||
className={classnames(
|
||||
"navbar__search-input",
|
||||
{ "search-bar-expanded": props.isSearchBarExpanded },
|
||||
{ "search-bar": !props.isSearchBarExpanded }
|
||||
)}
|
||||
onClick={loadAlgolia}
|
||||
onMouseOver={loadAlgolia}
|
||||
onFocus={toggleSearchIconClick}
|
||||
onBlur={toggleSearchIconClick}
|
||||
ref={searchBarRef}
|
||||
/>
|
||||
|
||||
<svg
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="19px"
|
||||
height="20px"
|
||||
viewBox="0 0 19 20"
|
||||
className={classnames("search-icon-keyboard", {
|
||||
"search-icon-hidden": props.isSearchBarExpanded,
|
||||
})}
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#979A9C"
|
||||
opacity="0.4"
|
||||
d="M3.5,0.5h12c1.7,0,3,1.3,3,3v13c0,1.7-1.3,3-3,3h-12c-1.7,0-3-1.3-3-3v-13C0.5,1.8,1.8,0.5,3.5,0.5z"
|
||||
/>
|
||||
<path fill="#979a9c" d="M11.8,6L8,15.1H7.1L10.8,6L11.8,6z" />
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Search
|
||||
@@ -1,336 +0,0 @@
|
||||
import Hogan from "hogan.js"
|
||||
import LunrSearchAdapter from "./lunar-search"
|
||||
import autocomplete from "autocomplete.js"
|
||||
import templates from "./templates"
|
||||
import utils from "./utils"
|
||||
import $ from "./zepto"
|
||||
|
||||
/**
|
||||
* Adds an autocomplete dropdown to an input field
|
||||
* @function DocSearch
|
||||
* @param {Object} options.searchData Read-only API key
|
||||
* @param {string} options.inputSelector CSS selector that targets the input
|
||||
* value.
|
||||
* @param {Object} [options.autocompleteOptions] Options to pass to the underlying autocomplete instance
|
||||
* @return {Object}
|
||||
*/
|
||||
const usage = `Usage:
|
||||
documentationSearch({
|
||||
searchData,
|
||||
inputSelector,
|
||||
[ appId ],
|
||||
[ autocompleteOptions.{hint,debug} ]
|
||||
})`
|
||||
class DocSearch {
|
||||
constructor({
|
||||
searchData,
|
||||
inputSelector,
|
||||
debug = false,
|
||||
queryDataCallback = null,
|
||||
autocompleteOptions = {
|
||||
debug: false,
|
||||
hint: false,
|
||||
autoselect: true,
|
||||
},
|
||||
transformData = false,
|
||||
queryHook = false,
|
||||
handleSelected = false,
|
||||
enhancedSearchInput = false,
|
||||
layout = "collumns",
|
||||
}) {
|
||||
DocSearch.checkArguments({
|
||||
searchData,
|
||||
inputSelector,
|
||||
})
|
||||
this.searchData = searchData
|
||||
this.input = DocSearch.getInputFromSelector(inputSelector)
|
||||
this.queryDataCallback = queryDataCallback || null
|
||||
const autocompleteOptionsDebug =
|
||||
autocompleteOptions && autocompleteOptions.debug
|
||||
? autocompleteOptions.debug
|
||||
: false
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
autocompleteOptions.debug = debug || autocompleteOptionsDebug
|
||||
this.autocompleteOptions = autocompleteOptions
|
||||
this.autocompleteOptions.cssClasses =
|
||||
this.autocompleteOptions.cssClasses || {}
|
||||
this.autocompleteOptions.cssClasses.prefix =
|
||||
this.autocompleteOptions.cssClasses.prefix || "ds"
|
||||
const inputAriaLabel =
|
||||
this.input &&
|
||||
typeof this.input.attr === "function" &&
|
||||
this.input.attr("aria-label")
|
||||
this.autocompleteOptions.ariaLabel =
|
||||
this.autocompleteOptions.ariaLabel || inputAriaLabel || "search input"
|
||||
|
||||
this.isSimpleLayout = layout === "simple"
|
||||
|
||||
this.client = new LunrSearchAdapter(this.searchData)
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
this.input = DocSearch.injectSearchBox(this.input)
|
||||
}
|
||||
this.autocomplete = autocomplete(this.input, autocompleteOptions, [
|
||||
{
|
||||
source: this.getAutocompleteSource(transformData, queryHook),
|
||||
templates: {
|
||||
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
|
||||
footer: templates.footer,
|
||||
empty: DocSearch.getEmptyTemplate(),
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const customHandleSelected = handleSelected
|
||||
this.handleSelected = customHandleSelected || this.handleSelected
|
||||
|
||||
// We prevent default link clicking if a custom handleSelected is defined
|
||||
if (customHandleSelected) {
|
||||
$(".algolia-autocomplete").on("click", ".ds-suggestions a", (event) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
}
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:selected",
|
||||
this.handleSelected.bind(null, this.autocomplete.autocomplete)
|
||||
)
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:shown",
|
||||
this.handleShown.bind(null, this.input)
|
||||
)
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
DocSearch.bindSearchBoxEvent()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the passed arguments are valid. Will throw errors otherwise
|
||||
* @function checkArguments
|
||||
* @param {object} args Arguments as an option object
|
||||
* @returns {void}
|
||||
*/
|
||||
static checkArguments(args) {
|
||||
if (!args.searchData) {
|
||||
throw new Error(usage)
|
||||
}
|
||||
|
||||
if (typeof args.inputSelector !== "string") {
|
||||
throw new Error(
|
||||
`Error: inputSelector:${args.inputSelector} must be a string. Each selector must match only one element and separated by ','`
|
||||
)
|
||||
}
|
||||
|
||||
if (!DocSearch.getInputFromSelector(args.inputSelector)) {
|
||||
throw new Error(
|
||||
`Error: No input element in the page matches ${args.inputSelector}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static injectSearchBox(input) {
|
||||
input.before(templates.searchBox)
|
||||
const newInput = input.prev().prev().find("input")
|
||||
input.remove()
|
||||
return newInput
|
||||
}
|
||||
|
||||
static bindSearchBoxEvent() {
|
||||
$('.searchbox [type="reset"]').on("click", function () {
|
||||
$("input#docsearch").focus()
|
||||
$(this).addClass("hide")
|
||||
autocomplete.autocomplete.setVal("")
|
||||
})
|
||||
|
||||
$("input#docsearch").on("keyup", () => {
|
||||
const searchbox = document.querySelector("input#docsearch")
|
||||
const reset = document.querySelector('.searchbox [type="reset"]')
|
||||
reset.className = "searchbox__reset hide"
|
||||
if (searchbox.value.length === 0) {
|
||||
reset.className += " hide"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the matching input from a CSS selector, null if none matches
|
||||
* @function getInputFromSelector
|
||||
* @param {string} selector CSS selector that matches the search
|
||||
* input of the page
|
||||
* @returns {void}
|
||||
*/
|
||||
static getInputFromSelector(selector) {
|
||||
const input = $(selector).filter("input")
|
||||
return input.length ? $(input[0]) : null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `source` method to be passed to autocomplete.js. It will query
|
||||
* the Algolia index and call the callbacks with the formatted hits.
|
||||
* @function getAutocompleteSource
|
||||
* @param {function} transformData An optional function to transform the hits
|
||||
* @param {function} queryHook An optional function to transform the query
|
||||
* @returns {function} Method to be passed as the `source` option of
|
||||
* autocomplete
|
||||
*/
|
||||
getAutocompleteSource(transformData, queryHook) {
|
||||
return (query, callback) => {
|
||||
if (queryHook) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
query = queryHook(query) || query
|
||||
}
|
||||
this.client.search(query).then((hits) => {
|
||||
if (
|
||||
this.queryDataCallback &&
|
||||
typeof this.queryDataCallback === "function"
|
||||
) {
|
||||
this.queryDataCallback(hits)
|
||||
}
|
||||
if (transformData) {
|
||||
hits = transformData(hits) || hits
|
||||
}
|
||||
callback(DocSearch.formatHits(hits))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Given a list of hits returned by the API, will reformat them to be used in
|
||||
// a Hogan template
|
||||
static formatHits(receivedHits) {
|
||||
const clonedHits = utils.deepClone(receivedHits)
|
||||
const hits = clonedHits.map((hit) => {
|
||||
if (hit._highlightResult) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
hit._highlightResult = utils.mergeKeyWithParent(
|
||||
hit._highlightResult,
|
||||
"hierarchy"
|
||||
)
|
||||
}
|
||||
return utils.mergeKeyWithParent(hit, "hierarchy")
|
||||
})
|
||||
|
||||
// Group hits by category / subcategory
|
||||
let groupedHits = utils.groupBy(hits, "lvl0")
|
||||
$.each(groupedHits, (level, collection) => {
|
||||
const groupedHitsByLvl1 = utils.groupBy(collection, "lvl1")
|
||||
const flattenedHits = utils.flattenAndFlagFirst(
|
||||
groupedHitsByLvl1,
|
||||
"isSubCategoryHeader"
|
||||
)
|
||||
groupedHits[level] = flattenedHits
|
||||
})
|
||||
groupedHits = utils.flattenAndFlagFirst(groupedHits, "isCategoryHeader")
|
||||
|
||||
// Translate hits into smaller objects to be send to the template
|
||||
return groupedHits.map((hit) => {
|
||||
const url = DocSearch.formatURL(hit)
|
||||
const category = utils.getHighlightedValue(hit, "lvl0")
|
||||
const subcategory = utils.getHighlightedValue(hit, "lvl1") || category
|
||||
const displayTitle = utils
|
||||
.compact([
|
||||
utils.getHighlightedValue(hit, "lvl2") || subcategory,
|
||||
utils.getHighlightedValue(hit, "lvl3"),
|
||||
utils.getHighlightedValue(hit, "lvl4"),
|
||||
utils.getHighlightedValue(hit, "lvl5"),
|
||||
utils.getHighlightedValue(hit, "lvl6"),
|
||||
])
|
||||
.join(
|
||||
'<span class="aa-suggestion-title-separator" aria-hidden="true"> › </span>'
|
||||
)
|
||||
const text = utils.getSnippetedValue(hit, "content")
|
||||
const isTextOrSubcategoryNonEmpty =
|
||||
(subcategory && subcategory !== "") ||
|
||||
(displayTitle && displayTitle !== "")
|
||||
const isLvl1EmptyOrDuplicate =
|
||||
!subcategory || subcategory === "" || subcategory === category
|
||||
const isLvl2 =
|
||||
displayTitle && displayTitle !== "" && displayTitle !== subcategory
|
||||
const isLvl1 =
|
||||
!isLvl2 && subcategory && subcategory !== "" && subcategory !== category
|
||||
const isLvl0 = !isLvl1 && !isLvl2
|
||||
|
||||
return {
|
||||
isLvl0,
|
||||
isLvl1,
|
||||
isLvl2,
|
||||
isLvl1EmptyOrDuplicate,
|
||||
isCategoryHeader: hit.isCategoryHeader,
|
||||
isSubCategoryHeader: hit.isSubCategoryHeader,
|
||||
isTextOrSubcategoryNonEmpty,
|
||||
category,
|
||||
subcategory,
|
||||
title: displayTitle,
|
||||
text,
|
||||
url,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static formatURL(hit) {
|
||||
const { url, anchor } = hit
|
||||
if (url) {
|
||||
const containsAnchor = url.indexOf("#") !== -1
|
||||
if (containsAnchor) return url
|
||||
else if (anchor) return `${hit.url}#${hit.anchor}`
|
||||
return url
|
||||
} else if (anchor) return `#${hit.anchor}`
|
||||
/* eslint-disable */
|
||||
console.warn("no anchor nor url for : ", JSON.stringify(hit))
|
||||
/* eslint-enable */
|
||||
return null
|
||||
}
|
||||
|
||||
static getEmptyTemplate() {
|
||||
return (args) => Hogan.compile(templates.empty).render(args)
|
||||
}
|
||||
|
||||
static getSuggestionTemplate(isSimpleLayout) {
|
||||
const stringTemplate = isSimpleLayout
|
||||
? templates.suggestionSimple
|
||||
: templates.suggestion
|
||||
const template = Hogan.compile(stringTemplate)
|
||||
return (suggestion) => template.render(suggestion)
|
||||
}
|
||||
|
||||
handleSelected(input, event, suggestion, datasetNumber, context = {}) {
|
||||
// Do nothing if click on the suggestion, as it's already a <a href>, the
|
||||
// browser will take care of it. This allow Ctrl-Clicking on results and not
|
||||
// having the main window being redirected as well
|
||||
if (context.selectionMethod === "click") {
|
||||
return
|
||||
}
|
||||
|
||||
input.setVal("")
|
||||
window.location.assign(suggestion.url)
|
||||
}
|
||||
|
||||
handleShown(input) {
|
||||
const middleOfInput = input.offset().left + input.width() / 2
|
||||
let middleOfWindow = $(document).width() / 2
|
||||
|
||||
if (isNaN(middleOfWindow)) {
|
||||
middleOfWindow = 900
|
||||
}
|
||||
|
||||
const alignClass =
|
||||
middleOfInput - middleOfWindow >= 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left"
|
||||
const otherAlignClass =
|
||||
middleOfInput - middleOfWindow < 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left"
|
||||
const autocompleteWrapper = $(".algolia-autocomplete")
|
||||
if (!autocompleteWrapper.hasClass(alignClass)) {
|
||||
autocompleteWrapper.addClass(alignClass)
|
||||
}
|
||||
|
||||
if (autocompleteWrapper.hasClass(otherAlignClass)) {
|
||||
autocompleteWrapper.removeClass(otherAlignClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DocSearch
|
||||
@@ -1,169 +0,0 @@
|
||||
/* eslint-disable */
|
||||
import lunr from 'lunr'
|
||||
lunr.tokenizer.separator = /[\s\-/]+/
|
||||
|
||||
class LunrSearchAdapter {
|
||||
constructor (searchData) {
|
||||
this.searchData = searchData
|
||||
this.init()
|
||||
this.titleHitsRes = []
|
||||
}
|
||||
|
||||
init () {
|
||||
const { searchData } = this
|
||||
this.lunrIndex = lunr(function () {
|
||||
this.ref('id')
|
||||
this.field('title', { boost: 200 })
|
||||
this.field('content', { boost: 2 })
|
||||
this.field('keywords', { boost: 100 })
|
||||
this.metadataWhitelist = ['position']
|
||||
searchData.forEach((d, i) => {
|
||||
const doc = {
|
||||
id: i,
|
||||
title: d.title,
|
||||
content: d.content,
|
||||
keywords: d.keywords
|
||||
}
|
||||
this.add(doc)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getLunrResult (input) {
|
||||
return this.lunrIndex.query(function (query) {
|
||||
const tokens = lunr.tokenizer(input)
|
||||
query.term(tokens, {
|
||||
boost: 10
|
||||
})
|
||||
query.term(tokens, {
|
||||
wildcard: lunr.Query.wildcard.TRAILING
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getHit (doc, formattedTitle, formattedContent) {
|
||||
return {
|
||||
hierarchy: {
|
||||
lvl0: doc.pageTitle || doc.title,
|
||||
lvl1: doc.type === 0 ? null : doc.title
|
||||
},
|
||||
url: doc.url,
|
||||
_snippetResult: formattedContent ? {
|
||||
content: {
|
||||
value: formattedContent,
|
||||
matchLevel: 'full'
|
||||
}
|
||||
} : null,
|
||||
_highlightResult: {
|
||||
hierarchy: {
|
||||
lvl0: {
|
||||
value: doc.type === 0 ? formattedTitle || doc.title : doc.pageTitle
|
||||
},
|
||||
lvl1:
|
||||
doc.type === 0
|
||||
? null
|
||||
: {
|
||||
value: formattedTitle || doc.title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTitleHit (doc, position, length) {
|
||||
const start = position[0]
|
||||
const end = position[0] + length
|
||||
const formattedTitle = doc.title.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length)
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getKeywordHit (doc, position, length) {
|
||||
const start = position[0]
|
||||
const end = position[0] + length
|
||||
const formattedTitle = doc.title + '<br /><i>Keywords: ' + doc.keywords.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.keywords.substring(start, end) + '</span>' + doc.keywords.substring(end, doc.keywords.length) + '</i>'
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getContentHit (doc, position) {
|
||||
const start = position[0]
|
||||
const end = position[0] + position[1]
|
||||
let previewStart = start
|
||||
let previewEnd = end
|
||||
let ellipsesBefore = true
|
||||
let ellipsesAfter = true
|
||||
for (let k = 0; k < 3; k++) {
|
||||
const nextSpace = doc.content.lastIndexOf(' ', previewStart - 2)
|
||||
const nextDot = doc.content.lastIndexOf('.', previewStart - 2)
|
||||
if ((nextDot > 0) && (nextDot > nextSpace)) {
|
||||
previewStart = nextDot + 1
|
||||
ellipsesBefore = false
|
||||
break
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewStart = 0
|
||||
ellipsesBefore = false
|
||||
break
|
||||
}
|
||||
previewStart = nextSpace + 1
|
||||
}
|
||||
for (let k = 0; k < 10; k++) {
|
||||
const nextSpace = doc.content.indexOf(' ', previewEnd + 1)
|
||||
const nextDot = doc.content.indexOf('.', previewEnd + 1)
|
||||
if ((nextDot > 0) && (nextDot < nextSpace)) {
|
||||
previewEnd = nextDot
|
||||
ellipsesAfter = false
|
||||
break
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewEnd = doc.content.length
|
||||
ellipsesAfter = false
|
||||
break
|
||||
}
|
||||
previewEnd = nextSpace
|
||||
}
|
||||
let preview = doc.content.substring(previewStart, start)
|
||||
if (ellipsesBefore) {
|
||||
preview = '... ' + preview
|
||||
}
|
||||
preview += '<span class="algolia-docsearch-suggestion--highlight">' + doc.content.substring(start, end) + '</span>'
|
||||
preview += doc.content.substring(end, previewEnd)
|
||||
if (ellipsesAfter) {
|
||||
preview += ' ...'
|
||||
}
|
||||
return this.getHit(doc, null, preview)
|
||||
}
|
||||
|
||||
search (input) {
|
||||
return new Promise((resolve, rej) => {
|
||||
const results = this.getLunrResult(input)
|
||||
const hits = []
|
||||
results.length > 5 && (results.length = 5)
|
||||
this.titleHitsRes = []
|
||||
this.contentHitsRes = []
|
||||
results.forEach(result => {
|
||||
const doc = this.searchData[result.ref]
|
||||
const { metadata } = result.matchData
|
||||
for (const i in metadata) {
|
||||
if (metadata[i].title) {
|
||||
if (!this.titleHitsRes.includes(result.ref)) {
|
||||
const position = metadata[i].title.position[0]
|
||||
hits.push(this.getTitleHit(doc, position, input.length))
|
||||
this.titleHitsRes.push(result.ref)
|
||||
}
|
||||
} else if (metadata[i].content) {
|
||||
const position = metadata[i].content.position[0]
|
||||
hits.push(this.getContentHit(doc, position))
|
||||
} else if (metadata[i].keywords) {
|
||||
const position = metadata[i].keywords.position[0]
|
||||
hits.push(this.getKeywordHit(doc, position, input.length))
|
||||
this.titleHitsRes.push(result.ref)
|
||||
}
|
||||
}
|
||||
})
|
||||
hits.length > 5 && (hits.length = 5)
|
||||
resolve(hits)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default LunrSearchAdapter
|
||||
@@ -1,110 +0,0 @@
|
||||
const prefix = "algolia-docsearch"
|
||||
const suggestionPrefix = `${prefix}-suggestion`
|
||||
const footerPrefix = `${prefix}-footer`
|
||||
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const templates = {
|
||||
suggestion: `
|
||||
<a class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
"
|
||||
aria-label="Link to the result"
|
||||
href="{{{url}}}"
|
||||
>
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
<span class="${suggestionPrefix}--category-header-lvl0">{{{category}}}</span>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--subcategory-column">
|
||||
<span class="${suggestionPrefix}--subcategory-column-text">{{{subcategory}}}</span>
|
||||
</div>
|
||||
{{#isTextOrSubcategoryNonEmpty}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--subcategory-inline">{{{subcategory}}}</div>
|
||||
<div class="${suggestionPrefix}--title">{{{title}}}</div>
|
||||
{{#text}}<div class="${suggestionPrefix}--text">{{{text}}}</div>{{/text}}
|
||||
</div>
|
||||
{{/isTextOrSubcategoryNonEmpty}}
|
||||
</div>
|
||||
</a>
|
||||
`,
|
||||
suggestionSimple: `
|
||||
<div class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
suggestion-layout-simple
|
||||
">
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
{{^isLvl0}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl0 ${suggestionPrefix}--category-header-item">{{{category}}}</span>
|
||||
{{^isLvl1}}
|
||||
{{^isLvl1EmptyOrDuplicate}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl1 ${suggestionPrefix}--category-header-item">
|
||||
{{{subcategory}}}
|
||||
</span>
|
||||
{{/isLvl1EmptyOrDuplicate}}
|
||||
{{/isLvl1}}
|
||||
{{/isLvl0}}
|
||||
<div class="${suggestionPrefix}--title ${suggestionPrefix}--category-header-item">
|
||||
{{#isLvl2}}
|
||||
{{{title}}}
|
||||
{{/isLvl2}}
|
||||
{{#isLvl1}}
|
||||
{{{subcategory}}}
|
||||
{{/isLvl1}}
|
||||
{{#isLvl0}}
|
||||
{{{category}}}
|
||||
{{/isLvl0}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
{{#text}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--text">{{{text}}}</div>
|
||||
</div>
|
||||
{{/text}}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
footer: `
|
||||
<div class="${footerPrefix}">
|
||||
</div>
|
||||
`,
|
||||
empty: `
|
||||
<div class="${suggestionPrefix}">
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--content ${suggestionPrefix}--no-results">
|
||||
<div class="${suggestionPrefix}--title">
|
||||
<div class="${suggestionPrefix}--text">
|
||||
No results found for query <b>"{{query}}"</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
searchBox: `
|
||||
<form novalidate="novalidate" onsubmit="return false;" class="searchbox">
|
||||
<div role="search" class="searchbox__wrapper">
|
||||
<input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input"/>
|
||||
|
||||
<button type="submit" title="Submit your search query." class="searchbox__submit" >
|
||||
<svg width=12 height=12 role="img" aria-label="Search">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"></symbol>
|
||||
<symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"></symbol>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
|
||||
export default templates
|
||||
@@ -1,270 +0,0 @@
|
||||
import $ from './zepto'
|
||||
|
||||
const utils = {
|
||||
/*
|
||||
* Move the content of an object key one level higher.
|
||||
* eg.
|
||||
* {
|
||||
* name: 'My name',
|
||||
* hierarchy: {
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* }
|
||||
* Will be converted to
|
||||
* {
|
||||
* name: 'My name',
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* @param {Object} object Main object
|
||||
* @param {String} property Main object key to move up
|
||||
* @return {Object}
|
||||
* @throws Error when key is not an attribute of Object or is not an object itself
|
||||
*/
|
||||
mergeKeyWithParent (object, property) {
|
||||
if (object[property] === undefined) {
|
||||
return object
|
||||
}
|
||||
if (typeof object[property] !== 'object') {
|
||||
return object
|
||||
}
|
||||
const newObject = $.extend({}, object, object[property])
|
||||
delete newObject[property]
|
||||
return newObject
|
||||
},
|
||||
/*
|
||||
* Group all objects of a collection by the value of the specified attribute
|
||||
* If the attribute is a string, use the lowercase form.
|
||||
*
|
||||
* eg.
|
||||
* groupBy([
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexS', category: 'dev'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ], 'category');
|
||||
* =>
|
||||
* {
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* }
|
||||
* @param {array} collection Array of objects to group
|
||||
* @param {String} property The attribute on which apply the grouping
|
||||
* @return {array}
|
||||
* @throws Error when one of the element does not have the specified property
|
||||
*/
|
||||
groupBy (collection, property) {
|
||||
const newCollection = {}
|
||||
$.each(collection, (index, item) => {
|
||||
if (item[property] === undefined) {
|
||||
throw new Error(`[groupBy]: Object has no key ${property}`)
|
||||
}
|
||||
let key = item[property]
|
||||
if (typeof key === 'string') {
|
||||
key = key.toLowerCase()
|
||||
}
|
||||
// fix #171 the given data type of docsearch hits might be conflict with the properties of the native Object,
|
||||
// such as the constructor, so we need to do this check.
|
||||
if (!Object.prototype.hasOwnProperty.call(newCollection, key)) {
|
||||
newCollection[key] = []
|
||||
}
|
||||
newCollection[key].push(item)
|
||||
})
|
||||
return newCollection
|
||||
},
|
||||
/*
|
||||
* Return an array of all the values of the specified object
|
||||
* eg.
|
||||
* values({
|
||||
* foo: 42,
|
||||
* bar: true,
|
||||
* baz: 'yep'
|
||||
* })
|
||||
* =>
|
||||
* [42, true, yep]
|
||||
* @param {object} object Object to extract values from
|
||||
* @return {array}
|
||||
*/
|
||||
values (object) {
|
||||
return Object.keys(object).map(key => object[key])
|
||||
},
|
||||
/*
|
||||
* Flattens an array
|
||||
* eg.
|
||||
* flatten([1, 2, [3, 4], [5, 6]])
|
||||
* =>
|
||||
* [1, 2, 3, 4, 5, 6]
|
||||
* @param {array} array Array to flatten
|
||||
* @return {array}
|
||||
*/
|
||||
flatten (array) {
|
||||
const results = []
|
||||
array.forEach(value => {
|
||||
if (!Array.isArray(value)) {
|
||||
results.push(value)
|
||||
return
|
||||
}
|
||||
value.forEach(subvalue => {
|
||||
results.push(subvalue)
|
||||
})
|
||||
})
|
||||
return results
|
||||
},
|
||||
/*
|
||||
* Flatten all values of an object into an array, marking each first element of
|
||||
* each group with a specific flag
|
||||
* eg.
|
||||
* flattenAndFlagFirst({
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* , 'isTop');
|
||||
* =>
|
||||
* [
|
||||
* {name: 'Tim', category: 'dev', isTop: true},
|
||||
* {name: 'Vincent', category: 'dev', isTop: false},
|
||||
* {name: 'AlexS', category: 'dev', isTop: false},
|
||||
* {name: 'Ben', category: 'sales', isTop: true},
|
||||
* {name: 'Jeremy', category: 'sales', isTop: false},
|
||||
* {name: 'AlexK', category: 'sales', isTop: false}
|
||||
* ]
|
||||
* @param {object} object Object to flatten
|
||||
* @param {string} flag Flag to set to true on first element of each group
|
||||
* @return {array}
|
||||
*/
|
||||
flattenAndFlagFirst (object, flag) {
|
||||
const values = this.values(object).map(collection =>
|
||||
collection.map((item, index) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item[flag] = index === 0
|
||||
return item
|
||||
})
|
||||
)
|
||||
return this.flatten(values)
|
||||
},
|
||||
/*
|
||||
* Removes all empty strings, null, false and undefined elements array
|
||||
* eg.
|
||||
* compact([42, false, null, undefined, '', [], 'foo']);
|
||||
* =>
|
||||
* [42, [], 'foo']
|
||||
* @param {array} array Array to compact
|
||||
* @return {array}
|
||||
*/
|
||||
compact (array) {
|
||||
const results = []
|
||||
array.forEach(value => {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
results.push(value)
|
||||
})
|
||||
return results
|
||||
},
|
||||
/*
|
||||
* Returns the highlighted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly
|
||||
* eg.
|
||||
* getHighlightedValue({
|
||||
* _highlightResult: {
|
||||
* text: {
|
||||
* value: '<mark>foo</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'foo'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>foo</mark>'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getHighlightedValue (object, property) {
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult.hierarchy_camel &&
|
||||
object._highlightResult.hierarchy_camel[property] &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' &&
|
||||
object._highlightResult.hierarchy_camel[property].value
|
||||
) {
|
||||
return object._highlightResult.hierarchy_camel[property].value
|
||||
}
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult &&
|
||||
object._highlightResult[property] &&
|
||||
object._highlightResult[property].value
|
||||
) {
|
||||
return object._highlightResult[property].value
|
||||
}
|
||||
return object[property]
|
||||
},
|
||||
/*
|
||||
* Returns the snippeted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly.
|
||||
* Will add starting and ending ellipsis (…) if we detect that a sentence is
|
||||
* incomplete
|
||||
* eg.
|
||||
* getSnippetedValue({
|
||||
* _snippetResult: {
|
||||
* text: {
|
||||
* value: '<mark>This is an unfinished sentence</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'This is an unfinished sentence'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>This is an unfinished sentence</mark>…'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getSnippetedValue (object, property) {
|
||||
if (
|
||||
!object._snippetResult ||
|
||||
!object._snippetResult[property] ||
|
||||
!object._snippetResult[property].value
|
||||
) {
|
||||
return object[property]
|
||||
}
|
||||
let snippet = object._snippetResult[property].value
|
||||
|
||||
if (snippet[0] !== snippet[0].toUpperCase()) {
|
||||
snippet = `…${snippet}`
|
||||
}
|
||||
if (['.', '!', '?'].indexOf(snippet[snippet.length - 1]) === -1) {
|
||||
snippet = `${snippet}…`
|
||||
}
|
||||
return snippet
|
||||
},
|
||||
/*
|
||||
* Deep clone an object.
|
||||
* Note: This will not clone functions and dates
|
||||
* @param {object} object Object to clone
|
||||
* @return {object}
|
||||
*/
|
||||
deepClone (object) {
|
||||
return JSON.parse(JSON.stringify(object))
|
||||
}
|
||||
}
|
||||
|
||||
export default utils
|
||||
@@ -1,2 +0,0 @@
|
||||
import zepto from 'autocomplete.js/zepto'
|
||||
export default zepto
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.search-icon {
|
||||
background-image: var(--ifm-navbar-search-input-icon);
|
||||
height: auto;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
line-height: 32px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-icon-keyboard {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.search-icon-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.searchbox__input::-webkit-search-decoration,
|
||||
.searchbox__input::-webkit-search-cancel-button {
|
||||
visibility: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.search-bar {
|
||||
width: 0 !important;
|
||||
background: none !important;
|
||||
padding: 0 !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.search-bar-expanded {
|
||||
width: 9rem !important;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
display: inline;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.search-icon-keyboard {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
background: none;
|
||||
}
|
||||
Reference in New Issue
Block a user