mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
86 Commits
next-auth@
...
@next-auth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2a07932b9 | ||
|
|
25c7ce1d2b | ||
|
|
227a233bd8 | ||
|
|
cf9f133aa3 | ||
|
|
2301c1be44 | ||
|
|
6e408e24bf | ||
|
|
f277989c69 | ||
|
|
6146e93288 | ||
|
|
1ff565da6c | ||
|
|
41f75cf870 | ||
|
|
dd591ed8d0 | ||
|
|
297bc2317f | ||
|
|
b170138e70 | ||
|
|
a307079e0f | ||
|
|
d52b7a6b7d | ||
|
|
30b69a07eb | ||
|
|
0d1757814f | ||
|
|
068f9b50b8 | ||
|
|
dac490b7a1 | ||
|
|
c0f51669e2 | ||
|
|
cbf8ce3510 | ||
|
|
1c19cc71df | ||
|
|
9d962a0056 | ||
|
|
8387c78e3f | ||
|
|
58e30a6af6 | ||
|
|
b7ff987baf | ||
|
|
782812a52b | ||
|
|
32f2a0cea3 | ||
|
|
3343ef18b2 | ||
|
|
6280fe9e10 | ||
|
|
52a2bf3e28 | ||
|
|
180c6252d9 | ||
|
|
362e981e6d | ||
|
|
5198eb19f7 | ||
|
|
0210cfccf3 | ||
|
|
e90925bea0 | ||
|
|
27a0b70d87 | ||
|
|
c676e93d8a | ||
|
|
f498e9cd0a | ||
|
|
2f3396d376 | ||
|
|
e62f879ebd | ||
|
|
f67959eb04 | ||
|
|
060953dacf | ||
|
|
30ad639d16 | ||
|
|
777da4302d | ||
|
|
733fd5f234 | ||
|
|
a787efc6be | ||
|
|
261968b9bb | ||
|
|
4dbbe5b2d9 | ||
|
|
d9df582fa8 | ||
|
|
af840b2106 | ||
|
|
ba89907d5a | ||
|
|
08eaeba79f | ||
|
|
c31eabfcc6 | ||
|
|
4423673424 | ||
|
|
281d0948b9 | ||
|
|
5246183c55 | ||
|
|
cb56cd44ca | ||
|
|
6758e1c6d1 | ||
|
|
462cca1087 | ||
|
|
ab48fcfe5b | ||
|
|
fe7aaeded8 | ||
|
|
c53c09ea5c | ||
|
|
4bcba45294 | ||
|
|
eb5a9bad9d | ||
|
|
9a6d95c17c | ||
|
|
5b2fc7b570 | ||
|
|
6f459225fa | ||
|
|
f38ee19a8a | ||
|
|
38a03ed7d8 | ||
|
|
e1eb684cc6 | ||
|
|
777b7b2f23 | ||
|
|
6132c3fa75 | ||
|
|
94beef77e6 | ||
|
|
490d59dd17 | ||
|
|
26a8c5fc6d | ||
|
|
e26ec74720 | ||
|
|
d13997e140 | ||
|
|
d6efda077d | ||
|
|
0a4b99de3b | ||
|
|
2d2dfecc9d | ||
|
|
2a2c3d7a45 | ||
|
|
82786ac440 | ||
|
|
dfe3e02132 | ||
|
|
92b38ed740 | ||
|
|
97feae7916 |
29
.eslintrc.js
29
.eslintrc.js
@@ -3,10 +3,27 @@ const path = require("path")
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: [path.resolve(__dirname, "./packages/**/tsconfig.eslint.json")],
|
||||
},
|
||||
extends: ["standard-with-typescript", "prettier"],
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts", "*.tsx"],
|
||||
extends: ["standard-with-typescript", "prettier"],
|
||||
rules: {
|
||||
camelcase: "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
},
|
||||
|
||||
parserOptions: {
|
||||
project: [
|
||||
path.resolve(__dirname, "./packages/**/tsconfig.eslint.json"),
|
||||
path.resolve(__dirname, "./apps/**/tsconfig.json"),
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
extends: ["prettier"],
|
||||
globals: {
|
||||
localStorage: "readonly",
|
||||
location: "readonly",
|
||||
@@ -14,10 +31,6 @@ module.exports = {
|
||||
},
|
||||
rules: {
|
||||
camelcase: "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
},
|
||||
plugins: ["jest"],
|
||||
env: {
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
1
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this issue after reading/searching through the [documentation](https://next-auth.js.org) first!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
2
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this [Provider](https://next-auth.js.org/providers/overview) related issue!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
@@ -67,6 +68,7 @@ body:
|
||||
- "Slack"
|
||||
- "Spotify"
|
||||
- "Strava"
|
||||
- "Todoist"
|
||||
- "Trakt"
|
||||
- "Twitch"
|
||||
- "Twitter"
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
3
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this [Adapter](https://next-auth.js.org/adapters/overview) related issue!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
@@ -30,8 +31,10 @@ body:
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@next-auth/supabase-adapter"
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@next-auth/xata-adapter"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
@@ -9,6 +9,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thank you very much for reaching out to us regarding the awesome feature that you believe should be included in the NextAuth.js library.
|
||||
|
||||
_NOTE: Feature requests are converted to [discussions (Ideas 💡)](https://github.com/nextauthjs/next-auth/discussions/categories/ideas). Make sure your idea hasn't been asked yet, and upvote the existing one before opening a new instead._
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/6_typescript.yml
vendored
1
.github/ISSUE_TEMPLATE/6_typescript.yml
vendored
@@ -17,6 +17,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Make sure you [link]() to external documentation if necessary and provide inline code examples like so:
|
||||
|
||||
```js
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/7_question.yml
vendored
1
.github/ISSUE_TEMPLATE/7_question.yml
vendored
@@ -9,6 +9,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
We are glad that you have a question about this library. Please provide the following information:
|
||||
|
||||
- type: textarea
|
||||
|
||||
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,9 +5,14 @@ Please fill out the information below to expedite the review and (hopefully)
|
||||
merge of your pull request!
|
||||
-->
|
||||
|
||||
> _NOTE_:
|
||||
>
|
||||
> - It's a good idea to open an issue first to discuss potential changes.
|
||||
> - Please make sure that you are _NOT_ opening a PR to fix a potential security vulnerability. Instead, please follow the [Security guidelines](../Security.md) to disclose the issue to us confidentially.
|
||||
|
||||
## ☕️ 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
|
||||
|
||||
@@ -23,6 +28,7 @@ Fixes: INSERT_ISSUE_LINK_HERE
|
||||
|
||||
## 📌 Resources
|
||||
|
||||
- [Contributing guidelines](./CONTRIBUTING.md)
|
||||
- [Code of conduct](./CODE_OF_CONDUCT.md)
|
||||
- [Security guidelines](../Security.md)
|
||||
- [Contributing guidelines](../CONTRIBUTING.md)
|
||||
- [Code of conduct](../CODE_OF_CONDUCT.md)
|
||||
- [Contributing to Open Source](https://kcd.im/pull-request)
|
||||
|
||||
6
.github/issue-labeler.yml
vendored
6
.github/issue-labeler.yml
vendored
@@ -30,8 +30,14 @@ prisma:
|
||||
sequelize:
|
||||
- "@next-auth/sequelize-adapter"
|
||||
|
||||
supabase:
|
||||
- "@next-auth/supabase-adapter"
|
||||
|
||||
typeorm-legacy:
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
|
||||
upstash-redis:
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
|
||||
xata:
|
||||
- "@next-auth/xata-adapter"
|
||||
|
||||
6
.github/pr-labeler.yml
vendored
6
.github/pr-labeler.yml
vendored
@@ -42,12 +42,18 @@ prisma:
|
||||
sequelize:
|
||||
- packages/adapter-sequelize/**
|
||||
|
||||
supabase:
|
||||
- packages/adapter-supabase/**
|
||||
|
||||
typeorm-legacy:
|
||||
- packages/adapter-typeorm-legacy/**
|
||||
|
||||
upstash-redis:
|
||||
- packages/adapter-upstash-redis/**
|
||||
|
||||
xata:
|
||||
- packages/adapter-xata/**
|
||||
|
||||
core:
|
||||
- packages/next-auth/src/**/*
|
||||
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -2,7 +2,7 @@ name: Code Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, beta, next]
|
||||
branches: [beta, next]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
@@ -18,10 +18,10 @@ jobs:
|
||||
language: ["javascript"]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
2
.github/workflows/label-issue.yml
vendored
2
.github/workflows/label-issue.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
name: Triage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: github/issue-labeler@v2.4.1
|
||||
- uses: github/issue-labeler@v2.5
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
configuration-path: ".github/issue-labeler.yml"
|
||||
|
||||
2
.github/workflows/label-pr.yml
vendored
2
.github/workflows/label-pr.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
name: Triage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v3
|
||||
- uses: actions/labeler@v4
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
configuration-path: ".github/pr-labeler.yml"
|
||||
|
||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -15,17 +15,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -49,17 +49,17 @@ jobs:
|
||||
environment: Production
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -81,15 +81,15 @@ jobs:
|
||||
environment: Preview
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN_PKG }}
|
||||
- name: Comment version on PR
|
||||
uses: NejcZdovc/comment-pr@v1
|
||||
uses: NejcZdovc/comment-pr@v2
|
||||
with:
|
||||
message:
|
||||
"🎉 Experimental release [published 📦️ on npm](https://npmjs.com/package/next-auth/v/${{ env.VERSION }})!\n \
|
||||
|
||||
2
.github/workflows/sync-examples.yml
vendored
2
.github/workflows/sync-examples.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Run GitHub File Sync
|
||||
# Can update to v1 when https://github.com/BetaHuhn/repo-file-sync-action/issues/168 is resolved
|
||||
uses: BetaHuhn/repo-file-sync-action@v1.16.5
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -65,6 +65,7 @@ dev.db*
|
||||
packages/adapter-prisma/prisma/dev.db
|
||||
packages/adapter-prisma/prisma/migrations
|
||||
db.sqlite
|
||||
packages/adapter-supabase/supabase/.branches
|
||||
|
||||
# Tests
|
||||
coverage
|
||||
|
||||
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting info@balazsorban.com, yo@ndo.dev, thvu@hey.com and me@iaincollins.com.
|
||||
reported by contacting hi@thvu.dev, info@balazsorban.com, yo@ndo.dev and me@iaincollins.com.
|
||||
All complaints will be reviewed and investigated and will result in a response
|
||||
that is deemed necessary and appropriate to the circumstances. The project team
|
||||
is obligated to maintain confidentiality with regard to the reporter of an
|
||||
|
||||
@@ -12,6 +12,8 @@ Please raise any significant new functionality or breaking change an issue for d
|
||||
|
||||
Anyone can be a contributor. Either you found a typo, or you have an awesome feature request you could implement, we encourage you to create a Pull Request.
|
||||
|
||||
Before contributing, we recommend you read the [Tour de Source: NextAuth.js](https://sourcegraph.com/notebooks/Tm90ZWJvb2s6MTc2MQ==) post to become more familiar with the libraries inner workings.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
- The latest changes are always in `main`, so please make your Pull Request against that branch.
|
||||
@@ -26,7 +28,6 @@ Anyone can be a contributor. Either you found a typo, or you have an awesome fea
|
||||
|
||||
A quick guide on how to setup _next-auth_ locally to work on it and test out any changes:
|
||||
|
||||
|
||||
1. Clone the repo:
|
||||
|
||||
```sh
|
||||
@@ -34,13 +35,21 @@ git clone git@github.com:nextauthjs/next-auth.git
|
||||
cd next-auth
|
||||
```
|
||||
|
||||
1. Install packages. Developing requires Node.js v16:
|
||||
2. Set up the correct pnpm version, using [Corepack](https://nodejs.org/api/corepack.html). Run the following in the project'a root:
|
||||
|
||||
```sh
|
||||
corepack enable pnpm
|
||||
```
|
||||
|
||||
(Now, if you run `pnpm --version`, it should print the same verion as the `packageManager` property in the [`package.json` file](https://github.com/nextauthjs/next-auth/blob/main/package.json))
|
||||
|
||||
3. Install packages. Developing requires Node.js v18:
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Populate `.env.local`:
|
||||
4. Populate `.env.local`:
|
||||
|
||||
Copy `apps/dev/.env.local.example` to `apps/dev/.env.local`, and add your env variables for each provider you want to test.
|
||||
|
||||
@@ -52,11 +61,12 @@ cp .env.local.example .env.local
|
||||
> NOTE: You can add any environment variables to .env.local that you would like to use in your dev app.
|
||||
> You can find the next-auth config under`apps/dev/pages/api/auth/[...nextauth].js`.
|
||||
|
||||
4. Start the developer application/server:
|
||||
5. Start the developer application/server:
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Your developer application will be available on `http://localhost:3000`
|
||||
|
||||
That's it! 🎉
|
||||
@@ -77,6 +87,7 @@ If you think your custom provider might be useful to others, we encourage you to
|
||||
|
||||
1. Add your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers) (Make sure you use a named default export, like `export default function YourProvider`!)
|
||||
2. Add provider documentation: [`www/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/www/docs/providers)
|
||||
3. Add provider logo svgs, like `google-dark.svg` (dark mode) and `google.svg` (light mode) to the `/packages/next-auth/provider-logos/` directory. Don't forget to set the provider's styling options in the `provider.style` config object.
|
||||
|
||||
That's it! 🎉 Others will be able to discover this provider much more easily now!
|
||||
|
||||
@@ -108,4 +119,4 @@ When accepting Pull Requests, make sure the following:
|
||||
|
||||
### Skipping a release
|
||||
|
||||
If a commit contains `[skip release]` in their message, it will be excluded from the commit analysis and won't participate in the release type determination. This is useful, if the PR being merged should not trigger a new `npm` release.
|
||||
If a commit contains `[skip release]` in their message, it will be excluded from the commit analysis and won't participate in the release type determination. This is useful, if the PR being merged should not trigger a new `npm` release.
|
||||
|
||||
@@ -13,7 +13,7 @@ If you contact us regarding a serious issue:
|
||||
- We will disclose the issue (and credit you, with your consent) once a fix to resolve the issue has been released.
|
||||
- If 90 days has elapsed and we still don't have a fix, we will disclose the issue publicly.
|
||||
|
||||
The best way to report an issue is by contacting us via email at info@balazsorban.com, yo@ndo.dev, thvu@hey.com and me@iaincollins.com, or raise a public issue requesting someone get in touch with you via whatever means you prefer for more details. (Please do not disclose sensitive details publicly at this stage.)
|
||||
The best way to report an issue is by contacting us via email at hi@thvu.dev, info@balazsorban.com, yo@ndo.dev and me@iaincollins.com, or raise a public issue requesting someone get in touch with you via whatever means you prefer for more details. (Please do not disclose sensitive details publicly at this stage.)
|
||||
|
||||
> For less serious issues (e.g. RFC compliance for unsupported flows or potential issues that may cause a problem in the future) it is appropriate to submit these publicly as bug reports or feature requests or to raise a question to open a discussion around them.
|
||||
|
||||
|
||||
@@ -48,4 +48,11 @@ EMAIL_FROM=user@gmail.com
|
||||
DATABASE_URL=
|
||||
|
||||
WIKIMEDIA_ID=
|
||||
WIKIMEDIA_SECRET=
|
||||
WIKIMEDIA_SECRET=
|
||||
|
||||
# Supabase Example Configuration
|
||||
# Supabase Example Configuration
|
||||
# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||
# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU
|
||||
# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
|
||||
# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs
|
||||
12
apps/dev/app/layout.tsx
Normal file
12
apps/dev/app/layout.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<head></head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
6
apps/dev/app/server-component/page.tsx
Normal file
6
apps/dev/app/server-component/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
@@ -17,9 +17,7 @@ export default function Footer() {
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/policy">
|
||||
<a>Policy</a>
|
||||
</Link>
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>{packageJSON.version}</em>
|
||||
|
||||
@@ -64,49 +64,37 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/">
|
||||
<a>Home</a>
|
||||
</Link>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/client">
|
||||
<a>Client</a>
|
||||
</Link>
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">
|
||||
<a>Server</a>
|
||||
</Link>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">
|
||||
<a>Protected</a>
|
||||
</Link>
|
||||
<Link href="/protected">Protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected-ssr">
|
||||
<a>Protected(SSR)</a>
|
||||
</Link>
|
||||
<Link href="/protected-ssr">Protected(SSR)</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/api-example">
|
||||
<a>API</a>
|
||||
</Link>
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/credentials">
|
||||
<a>Credentials</a>
|
||||
</Link>
|
||||
<Link href="/credentials">Credentials</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/email">
|
||||
<a>Email</a>
|
||||
</Link>
|
||||
<Link href="/email">Email</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/middleware-protected">
|
||||
<a>Middleware protected</a>
|
||||
</Link>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-client-rls">Supabase RLS</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -4,5 +4,6 @@ module.exports = {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"clean": "rm -rf .next",
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"email": "fake-smtp-server",
|
||||
@@ -15,16 +16,20 @@
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
"next": "12.2.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"next": "13.0.2",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsonwebtoken": "^8.5.5",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import NextAuth from "next-auth"
|
||||
import type { NextAuthOptions } from "next-auth"
|
||||
import jwt from "jsonwebtoken"
|
||||
|
||||
// Providers
|
||||
import Apple from "next-auth/providers/apple"
|
||||
@@ -42,6 +43,7 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { Client as FaunaClient } from "faunadb"
|
||||
import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
|
||||
// Add an adapter you want to test here.
|
||||
const adapters = {
|
||||
@@ -68,6 +70,12 @@ const adapters = {
|
||||
if (process.env.NODE_ENV !== "production") global.fauna = client
|
||||
return FaunaAdapter(client)
|
||||
},
|
||||
supabase() {
|
||||
return SupabaseAdapter({
|
||||
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
})
|
||||
},
|
||||
noop() {
|
||||
return undefined
|
||||
},
|
||||
@@ -75,7 +83,24 @@ const adapters = {
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: adapters.noop(),
|
||||
debug: true,
|
||||
callbacks: {
|
||||
async session({ session, user }) {
|
||||
// NOTE: this is needed when using Supabase with RLS. Otherwise this callback can be removed.
|
||||
const signingSecret = process.env.SUPABASE_JWT_SECRET
|
||||
if (signingSecret) {
|
||||
const payload = {
|
||||
aud: "authenticated",
|
||||
exp: Math.floor(new Date(session.expires).getTime() / 1000),
|
||||
sub: user.id,
|
||||
email: user.email,
|
||||
role: "authenticated",
|
||||
}
|
||||
session.supabaseAccessToken = jwt.sign(payload, signingSecret)
|
||||
}
|
||||
return session
|
||||
},
|
||||
},
|
||||
debug: process.env.NODE_ENV !== "production",
|
||||
theme: {
|
||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||
brandColor: "#1786fb",
|
||||
|
||||
@@ -9,6 +9,7 @@ export default async (req, res) => {
|
||||
res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
session,
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from '../auth/[...nextauth]';
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
res.json(session)
|
||||
}
|
||||
|
||||
30
apps/dev/pages/api/examples/supabase-rls.js
Normal file
30
apps/dev/pages/api/examples/supabase-rls.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// This is an example of how to query data from Supabase with RLS.
|
||||
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (!session)
|
||||
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
|
||||
|
||||
const { supabaseAccessToken } = session
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
// Now you can query with RLS enabled.
|
||||
const { data, error } = await supabase.from("users").select("*")
|
||||
|
||||
res.send(JSON.stringify({ supabaseAccessToken, data, error }, null, 2))
|
||||
}
|
||||
49
apps/dev/pages/supabase-client-rls.js
Normal file
49
apps/dev/pages/supabase-client-rls.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import Layout from "../components/layout"
|
||||
import { useState, useEffect } from "react"
|
||||
import { useSession } from "next-auth/react"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default function Page() {
|
||||
const { data: session } = useSession()
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
console.log(session)
|
||||
// User is logged in, let's fetch their data.
|
||||
const { supabaseAccessToken } = session
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: { Authorization: `Bearer ${supabaseAccessToken}` },
|
||||
},
|
||||
}
|
||||
)
|
||||
// Fetch data with RLS enabled.
|
||||
supabase
|
||||
.from("users")
|
||||
.select("*")
|
||||
.then(({ data }) => setData(data))
|
||||
}
|
||||
}, [session])
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Fetch Data from Supabase with RLS</h1>
|
||||
<h2>Client-side data fetching with RLS:</h2>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
<h2>API Example</h2>
|
||||
<p>
|
||||
You can also use Supabase in API routes. See the code in the
|
||||
`/pages/api/examples/supabase-rls.js` file.
|
||||
</p>
|
||||
<p>
|
||||
<em>You must be signed in to see responses.</em>
|
||||
</p>
|
||||
<p>/api/examples/supabase-rls</p>
|
||||
<iframe src="/api/examples/supabase-rls" />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
68
apps/dev/pages/supabase-ssr.js
Normal file
68
apps/dev/pages/supabase-ssr.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
// and fetching data from Supabase with RLS enabled.
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function Page({ data, session }) {
|
||||
// If no session exists, display access denied message
|
||||
if (!session) {
|
||||
return (
|
||||
<Layout>
|
||||
<AccessDenied />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// If session exists, display content
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Protected Page</h1>
|
||||
<p>Data fetched during SSR from Supabase with RSL enabled:</p>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
|
||||
if (!session)
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
data: null,
|
||||
error: "No session",
|
||||
},
|
||||
}
|
||||
|
||||
const { supabaseAccessToken } = session
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
// Now you can query with RLS enabled.
|
||||
const { data, error } = await supabase.from("users").select("*")
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
data,
|
||||
error,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
@@ -15,7 +19,20 @@
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules", "jest.config.js"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.js"
|
||||
]
|
||||
}
|
||||
|
||||
20
apps/dev/types/nextauth.d.ts
vendored
Normal file
20
apps/dev/types/nextauth.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||
*/
|
||||
interface Session {
|
||||
// A JWT which can be used as Authorization header with supabase-js for RLS.
|
||||
supabaseAccessToken?: string
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
} & User
|
||||
}
|
||||
|
||||
interface User {
|
||||
foo: string
|
||||
}
|
||||
}
|
||||
104
apps/example-nextjs/.gitignore
vendored
104
apps/example-nextjs/.gitignore
vendored
@@ -1,110 +1,20 @@
|
||||
# Logs
|
||||
.DS_Store
|
||||
|
||||
node_modules/
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.yarn-integrity
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
.vercel
|
||||
.now
|
||||
.env.local
|
||||
|
||||
.DS_Store
|
||||
.env*.local
|
||||
@@ -17,9 +17,7 @@ export default function Footer() {
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/policy">
|
||||
<a>Policy</a>
|
||||
</Link>
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
||||
|
||||
@@ -67,39 +67,25 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/">
|
||||
<a>Home</a>
|
||||
</Link>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/client">
|
||||
<a>Client</a>
|
||||
</Link>
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">
|
||||
<a>Server</a>
|
||||
</Link>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">
|
||||
<a>Protected</a>
|
||||
</Link>
|
||||
<Link href="/protected">Protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/api-example">
|
||||
<a>API</a>
|
||||
</Link>
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/admin">
|
||||
<a>Admin</a>
|
||||
</Link>
|
||||
<Link href="/admin">Admin</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/me">
|
||||
<a>Me</a>
|
||||
</Link>
|
||||
<Link href="/me">Me</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import Header from "./header"
|
||||
import Footer from "./footer"
|
||||
import type { ReactChildren } from "react"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export default function Layout({ children }: Props) {
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
@@ -13,13 +13,12 @@ export default function ServerSidePage({ session }: { session: Session }) {
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>unstable_getServerSideProps()</strong>.
|
||||
in <strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||
<strong>unstable_getServerSideProps()</strong> is the recommended
|
||||
approach if you need to support Server Side Rendering with
|
||||
authentication.
|
||||
<strong>getServerSideProps()</strong> is the recommended approach if you
|
||||
need to support Server Side Rendering with authentication.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require
|
||||
|
||||
12
apps/playground-nuxt/.editorconfig
Normal file
12
apps/playground-nuxt/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
4
apps/playground-nuxt/.eslintignore
Normal file
4
apps/playground-nuxt/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
tsconfig.json
|
||||
package.json
|
||||
10
apps/playground-nuxt/.eslintrc
Normal file
10
apps/playground-nuxt/.eslintrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": [
|
||||
"@nuxtjs/eslint-config-typescript"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"off"
|
||||
]
|
||||
}
|
||||
}
|
||||
52
apps/playground-nuxt/.gitignore
vendored
Normal file
52
apps/playground-nuxt/.gitignore
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
*.log*
|
||||
|
||||
# Temp directories
|
||||
.temp
|
||||
.tmp
|
||||
.cache
|
||||
|
||||
# Yarn
|
||||
**/.yarn/cache
|
||||
**/.yarn/*state*
|
||||
|
||||
# Generated dirs
|
||||
dist
|
||||
|
||||
# Nuxt
|
||||
.nuxt
|
||||
.output
|
||||
.vercel_build_output
|
||||
.build-*
|
||||
.env
|
||||
.netlify
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Testing
|
||||
reports
|
||||
coverage
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# Intellij idea
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
.vercel
|
||||
1
apps/playground-nuxt/.nuxtrc
Normal file
1
apps/playground-nuxt/.nuxtrc
Normal file
@@ -0,0 +1 @@
|
||||
imports.autoImport=false
|
||||
108
apps/playground-nuxt/README.md
Normal file
108
apps/playground-nuxt/README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# NextAuth + Nuxt 3 Playground
|
||||
|
||||
NextAuth.js is committed to bringing easy authentication to other frameworks. [#2294](https://github.com/nextauthjs/next-auth/issues/2294)
|
||||
|
||||
Nuxt 3 support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like` @next-auth/nuxt.`
|
||||
|
||||
This package uses Nuxt's [module starter](https://github.com/nuxt/starter/tree/module).
|
||||
|
||||
Demo: https://next-auth-nuxt-demo.vercel.app
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Add the module to the modules section of `nuxt.config.ts`:
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
// temporary module name.
|
||||
modules: ['next-auth-nuxt'],
|
||||
// https://v3.nuxtjs.org/migration/runtime-config#runtime-config
|
||||
runtimeConfig: {
|
||||
secret: process.env.NEXTAUTH_SECRET
|
||||
github: {
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
}
|
||||
},
|
||||
// https://v3.nuxtjs.org/guide/concepts/esm#aliasing-libraries
|
||||
// Fix for GithubProvider (or whichever provider you choose) is not a function error in Vite
|
||||
alias: {
|
||||
'next-auth/providers/github': 'node_modules/next-auth/providers/github.js'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Add API route
|
||||
|
||||
To add `NextAuth.js` to a project create a file called `[...].ts` in `server/api/auth`. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
|
||||
|
||||
```ts
|
||||
// ~/server/api/auth/[...].ts
|
||||
import { NextAuthNuxtHandler } from 'next-auth-nuxt/handler'
|
||||
import GithubProvider from 'next-auth/providers/github'
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: runtimeConfig.github.clientId,
|
||||
clientSecret: runtimeConfig.github.clientSecret
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export default NextAuthNuxtHandler(authOptions)
|
||||
```
|
||||
|
||||
All requests to `/api/auth/*` (`signIn`, `callback`, `signOut`, etc.) will automatically be handled by NextAuth.js.
|
||||
|
||||
### Frontend - Add Vue Composable
|
||||
|
||||
The `useSession()` Vue Composable is the easiest way to check if someone is signed in.
|
||||
|
||||
```html
|
||||
<script setup lang="ts">
|
||||
const { data: session } = useSession()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="session">
|
||||
Signed in as {{ session.user.email }} <br />
|
||||
<button @click="signOut">Sign out</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
Not signed in <br />
|
||||
<button @click="signIn">Sign in</button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Backend - API Route
|
||||
|
||||
To protect an API Route, you can use the `getServerSession()` method.
|
||||
|
||||
```ts
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '~/server/api/auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
content: 'This is protected content. You can access this content because you are signed in.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'You must be signed in to view the protected content on this page.'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
- Run `pnpm dev:generate` to generate type stubs.
|
||||
- Use `pnpm dev` to start `playground` in development mode.
|
||||
1
apps/playground-nuxt/client.d.ts
vendored
Normal file
1
apps/playground-nuxt/client.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dist/runtime/client'
|
||||
1
apps/playground-nuxt/handler.d.ts
vendored
Normal file
1
apps/playground-nuxt/handler.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dist/runtime/server/handler'
|
||||
49
apps/playground-nuxt/package.json
Normal file
49
apps/playground-nuxt/package.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "next-auth-nuxt",
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"packageManager": "pnpm@7.1.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/module.cjs",
|
||||
"types": "./dist/types.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs"
|
||||
},
|
||||
"./handler": {
|
||||
"import": "./dist/runtime/server/handler.mjs",
|
||||
"types": "./dist/runtime/server/handler.d.ts"
|
||||
},
|
||||
"./client": {
|
||||
"import": "./dist/runtime/client/index.mjs",
|
||||
"types": "./dist/runtime/client/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"handler.d.ts",
|
||||
"client.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepack": "nuxt-module-build",
|
||||
"dev": "pnpm prepack && nuxi dev playground",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:build:vercel": "NITRO_PRESET=vercel nuxi build playground",
|
||||
"dev:prepare": "nuxt-module-build --stub && nuxi prepare playground"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^3.0.0-rc.13",
|
||||
"h3": "^0.8.6",
|
||||
"next-auth": "^4.16.2",
|
||||
"pathe": "^0.3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/module-builder": "^0.2.0",
|
||||
"@nuxt/schema": "^3.0.0-rc.12",
|
||||
"@nuxtjs/eslint-config-typescript": "^11.0.0",
|
||||
"eslint": "^8.26.0",
|
||||
"nuxt": "^3.0.0-rc.13",
|
||||
"next-auth-nuxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
4
apps/playground-nuxt/playground/.env.example
Normal file
4
apps/playground-nuxt/playground/.env.example
Normal file
@@ -0,0 +1,4 @@
|
||||
GITHUB_CLIENT_ID=
|
||||
GITHUB_CLIENT_SECRET=
|
||||
NEXTAUTH_URL=
|
||||
NEXTAUTH_SECRET=
|
||||
40
apps/playground-nuxt/playground/app.vue
Normal file
40
apps/playground-nuxt/playground/app.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<NuxtPage />
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
li,
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
iframe {
|
||||
background: #ccc;
|
||||
border: 1px solid #ccc;
|
||||
height: 10rem;
|
||||
width: 100%;
|
||||
border-radius: .5rem;
|
||||
filter: invert(1);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Access Denied</h1>
|
||||
<p>
|
||||
<a href="/api/auth/signin">You must be signed in to view this page</a>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
30
apps/playground-nuxt/playground/components/Footer.vue
Normal file
30
apps/playground-nuxt/playground/components/Footer.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<footer class="fotter">
|
||||
<hr>
|
||||
<ul class="navItems">
|
||||
<li class="navItem">
|
||||
<a href="https://github.com/nextauthjs/next-auth/tree/main/apps/playground-nuxt">Demo GitHub</a>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<a href="https://next-auth.js.org">Next.js Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.footer {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.navItems {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
155
apps/playground-nuxt/playground/components/Header.vue
Normal file
155
apps/playground-nuxt/playground/components/Header.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<script setup lang="ts">
|
||||
import { useSession, signIn, signOut, computed } from '#imports'
|
||||
|
||||
const { data: session, status } = useSession()
|
||||
const loading = computed(() => status.value === 'loading')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<div class="signedInStatus">
|
||||
<p :class="['nojs-show', !session && loading ? 'loading' : 'loaded']">
|
||||
<template v-if="session">
|
||||
<span v-if="session.user?.image" :style="{ backgroundImage: `url(${session.user.image})` }" class="avatar" />
|
||||
<span class="signedInText">
|
||||
<small>Signed in as</small><br>
|
||||
<strong>{{ session.user?.email || session.user?.name }}</strong>
|
||||
</span>
|
||||
<a href="/api/auth/signout" class="button" @click.prevent="signOut">Sign out</a>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="notSignedInText">You are not signed in</span>
|
||||
<a href="/api/auth/signin" class="buttonPrimary" @click.prevent="signIn">Sign in</a>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="navItems">
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/">
|
||||
Home
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/client">
|
||||
Client
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/server">
|
||||
Server
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/protected">
|
||||
Protected
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/api-example">
|
||||
API
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.nojs-show {
|
||||
opacity: 1;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.signedInStatus {
|
||||
display: block;
|
||||
min-height: 4rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.loaded {
|
||||
position: relative;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 .6rem .6rem;
|
||||
padding: .6rem 1rem;
|
||||
margin: 0;
|
||||
background-color: rgba(0,0,0,.05);
|
||||
transition: all 0.2s ease-in;
|
||||
}
|
||||
|
||||
.loading {
|
||||
top: -2rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.signedInText,
|
||||
.notSignedInText {
|
||||
position: absolute;
|
||||
padding-top: .8rem;
|
||||
left: 1rem;
|
||||
right: 6.5rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: inherit;
|
||||
z-index: 1;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
.signedInText {
|
||||
padding-top: 0rem;
|
||||
left: 4.6rem;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 2rem;
|
||||
float: left;
|
||||
height: 2.8rem;
|
||||
width: 2.8rem;
|
||||
background-color: white;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.button,
|
||||
.buttonPrimary {
|
||||
float: right;
|
||||
margin-right: -.4rem;
|
||||
font-weight: 500;
|
||||
border-radius: .3rem;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
padding: .7rem .8rem;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
background-color: transparent;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.buttonPrimary {
|
||||
background-color: #346df1;
|
||||
border-color: #346df1;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: .7rem 1.4rem;
|
||||
}
|
||||
|
||||
.buttonPrimary:hover {
|
||||
box-shadow: inset 0 0 5rem rgba(0,0,0,0.2)
|
||||
}
|
||||
|
||||
.navItems {
|
||||
margin-bottom: 2rem;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
20
apps/playground-nuxt/playground/nuxt.config.ts
Normal file
20
apps/playground-nuxt/playground/nuxt.config.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import MyModule from '../src/module'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
MyModule
|
||||
],
|
||||
// https://v3.nuxtjs.org/migration/runtime-config#runtime-config
|
||||
runtimeConfig: {
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
github: {
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
}
|
||||
},
|
||||
// https://v3.nuxtjs.org/guide/concepts/esm#aliasing-libraries
|
||||
// Fix for GithubProvider is not a function error in Vite
|
||||
alias: {
|
||||
'next-auth/providers/github': 'node_modules/next-auth/providers/github.js'
|
||||
}
|
||||
})
|
||||
4
apps/playground-nuxt/playground/package.json
Normal file
4
apps/playground-nuxt/playground/package.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "playground",
|
||||
"private": true
|
||||
}
|
||||
15
apps/playground-nuxt/playground/pages/api-example.vue
Normal file
15
apps/playground-nuxt/playground/pages/api-example.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>API Example</h1>
|
||||
<p>The examples below show responses from the example API endpoints.</p>
|
||||
<p>
|
||||
<em>You must be signed in to see responses.</em>
|
||||
</p>
|
||||
<h2>Session</h2>
|
||||
<p>/api/examples/session</p>
|
||||
<iframe src="/api/examples/session" />
|
||||
<h2>JSON Web Token</h2>
|
||||
<p>/api/examples/jwt</p>
|
||||
<iframe src="/api/examples/jwt" />
|
||||
</div>
|
||||
</template>
|
||||
18
apps/playground-nuxt/playground/pages/client.vue
Normal file
18
apps/playground-nuxt/playground/pages/client.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Client Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>useSession()</strong> Vue Composable in the <strong><Header/></strong> component.
|
||||
</p>
|
||||
<p>
|
||||
The <strong>useSession()</strong> Vue Composable is easy to use and allows pages to render very quickly.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of this approach is that session state is shared between pages by using a provided session via <strong>Vue Plugin</strong> so
|
||||
that navigation between pages using <strong>useSession()</strong> is very fast.
|
||||
</p>
|
||||
<p>
|
||||
The disadvantage of <strong>useSession()</strong> is that it requires client side JavaScript.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
8
apps/playground-nuxt/playground/pages/index.vue
Normal file
8
apps/playground-nuxt/playground/pages/index.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Nuxt 3 + NextAuth.js Example</h1>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use <a href="https://v3.nuxtjs.org/">Nuxt 3</a> with <a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
19
apps/playground-nuxt/playground/pages/protected.vue
Normal file
19
apps/playground-nuxt/playground/pages/protected.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { useSession, useFetch, useLazyFetch } from '#imports'
|
||||
import AccessDenied from '~/components/AccessDenied.vue'
|
||||
|
||||
const { data: session } = useSession()
|
||||
const { data } = await useLazyFetch('/api/examples/protected', {
|
||||
server: false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<AccessDenied v-if="!session" />
|
||||
<template v-else>
|
||||
<h1>Protected Page</h1>
|
||||
<p><strong>{{ data?.content || "\u00a0" }}</strong></p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
24
apps/playground-nuxt/playground/pages/server.vue
Normal file
24
apps/playground-nuxt/playground/pages/server.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { useFetch } from '#imports'
|
||||
|
||||
await useFetch('/api/examples/session')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>getServerSession()</strong> method inside an api route and is fetched using the <strong>useFetch()</strong> composable.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getServerSession()</strong> is the recommended approach if you need to
|
||||
support Server Side Rendering with authentication.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require client side JavaScript.
|
||||
</p>
|
||||
<p>
|
||||
The disadvantage of Server Side Rendering is that this page is slower to render.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
17
apps/playground-nuxt/playground/server/api/auth/[...].ts
Normal file
17
apps/playground-nuxt/playground/server/api/auth/[...].ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NextAuthNuxtHandler } from 'next-auth-nuxt/handler'
|
||||
import GithubProvider from 'next-auth/providers/github'
|
||||
import type { NextAuthOptions } from 'next-auth'
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: runtimeConfig.github.clientId,
|
||||
clientSecret: runtimeConfig.github.clientSecret
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
export default NextAuthNuxtHandler(authOptions)
|
||||
10
apps/playground-nuxt/playground/server/api/examples/jwt.ts
Normal file
10
apps/playground-nuxt/playground/server/api/examples/jwt.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { getToken } from 'next-auth/jwt'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// @ts-expect-error: cookies property is not present in h3
|
||||
event.req.cookies = parseCookies(event)
|
||||
const token = await getToken({
|
||||
req: event.req
|
||||
})
|
||||
return token
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '../auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
content: 'This is protected content. You can access this content because you are signed in.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'You must be signed in to view the protected content on this page.'
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '../auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
return session
|
||||
})
|
||||
6386
apps/playground-nuxt/pnpm-lock.yaml
generated
Normal file
6386
apps/playground-nuxt/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
apps/playground-nuxt/pnpm-workspace.yaml
Normal file
2
apps/playground-nuxt/pnpm-workspace.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
packages:
|
||||
- playground
|
||||
40
apps/playground-nuxt/src/module.ts
Normal file
40
apps/playground-nuxt/src/module.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import { addImports, addPlugin, defineNuxtModule, extendViteConfig } from '@nuxt/kit'
|
||||
import { resolve } from 'pathe'
|
||||
|
||||
export interface ModuleOptions {
|
||||
}
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
name: 'next-auth-nuxt',
|
||||
configKey: 'auth'
|
||||
},
|
||||
defaults: {
|
||||
},
|
||||
async setup (_options, nuxt) {
|
||||
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
|
||||
nuxt.options.build.transpile.push(runtimeDir)
|
||||
|
||||
addPlugin(resolve(runtimeDir, 'plugin.client'))
|
||||
|
||||
// Composables are auto-imported in client.
|
||||
const client = resolve(runtimeDir, 'client')
|
||||
await addImports([
|
||||
{ name: 'getSession', from: client },
|
||||
{ name: 'getCsrfToken', from: client },
|
||||
{ name: 'getProviders', from: client },
|
||||
{ name: 'signIn', from: client },
|
||||
{ name: 'signOut', from: client },
|
||||
{ name: 'useSession', from: client }
|
||||
])
|
||||
|
||||
// We can safely expose this to client.
|
||||
extendViteConfig((config) => {
|
||||
config.define = config.define || {}
|
||||
config.define['process.env.NEXTAUTH_URL'] = JSON.stringify(process.env.NEXTAUTH_URL)
|
||||
config.define['process.env.NEXTAUTH_URL_INTERNAL'] = JSON.stringify(process.env.NEXTAUTH_URL_INTERNAL)
|
||||
config.define['process.env.VERCEL_URL'] = JSON.stringify(process.env.VERCEL_URL)
|
||||
})
|
||||
}
|
||||
})
|
||||
369
apps/playground-nuxt/src/runtime/client/index.ts
Normal file
369
apps/playground-nuxt/src/runtime/client/index.ts
Normal file
@@ -0,0 +1,369 @@
|
||||
import type { NextAuthClientConfig } from 'next-auth/client/_utils'
|
||||
import type { Plugin, Ref } from 'vue'
|
||||
import { ref, reactive, computed, inject, toRefs } from 'vue'
|
||||
import { BroadcastChannel, apiBaseUrl, fetchData, now } from 'next-auth/client/_utils'
|
||||
import type { Session } from 'next-auth'
|
||||
import type {
|
||||
BuiltInProviderType,
|
||||
RedirectableProviderType
|
||||
} from 'next-auth/providers'
|
||||
import type { H3EventContext } from 'h3'
|
||||
import parseUrl from '../lib/parse-url'
|
||||
import _logger, { proxyLogger } from '../lib/logger'
|
||||
import type {
|
||||
ClientSafeProvider,
|
||||
LiteralUnion,
|
||||
SessionProviderProps,
|
||||
SignInAuthorizationParams,
|
||||
SignInOptions,
|
||||
SignInResponse,
|
||||
SignOutParams,
|
||||
SignOutResponse
|
||||
} from '../types'
|
||||
|
||||
// This behaviour mirrors the default behaviour for getting the site name that
|
||||
// happens server side in server/index.js
|
||||
// 1. An empty value is legitimate when the code is being invoked client side as
|
||||
// relative URLs are valid in that context and so defaults to empty.
|
||||
// 2. When invoked server side the value is picked up from an environment
|
||||
// variable and defaults to 'http://localhost:3000'.
|
||||
const __NEXTAUTH: NextAuthClientConfig = {
|
||||
baseUrl: parseUrl(process.env.NEXTAUTH_URL ?? process.env.VERCEL_URL).origin,
|
||||
basePath: parseUrl(process.env.NEXTAUTH_URL).path,
|
||||
baseUrlServer: parseUrl(
|
||||
process.env.NEXTAUTH_URL_INTERNAL ??
|
||||
process.env.NEXTAUTH_URL ??
|
||||
process.env.VERCEL_URL
|
||||
).origin,
|
||||
basePathServer: parseUrl(
|
||||
process.env.NEXTAUTH_URL_INTERNAL ?? process.env.NEXTAUTH_URL
|
||||
).path,
|
||||
_lastSync: 0,
|
||||
_session: undefined,
|
||||
_getSession: () => {}
|
||||
}
|
||||
|
||||
export interface CtxOrReq {
|
||||
req?: H3EventContext['req']
|
||||
event?: { req: H3EventContext['req'] }
|
||||
}
|
||||
|
||||
export type GetSessionParams = CtxOrReq & {
|
||||
event?: 'storage' | 'timer' | 'hidden' | string
|
||||
triggerEvent?: boolean
|
||||
broadcast?: boolean
|
||||
}
|
||||
|
||||
const logger = proxyLogger(_logger, __NEXTAUTH.basePath)
|
||||
|
||||
const broadcast = BroadcastChannel()
|
||||
|
||||
function isServer () {
|
||||
return (process as any).server
|
||||
}
|
||||
|
||||
export async function getSession (params?: GetSessionParams) {
|
||||
const session = await fetchData<Session>(
|
||||
'session',
|
||||
__NEXTAUTH,
|
||||
logger,
|
||||
params
|
||||
)
|
||||
if (params?.broadcast ?? true) { broadcast.post({ event: 'session', data: { trigger: 'getSession' } }) }
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Cross Site Request Forgery Token (CSRF Token)
|
||||
* required to make POST requests (e.g. for signing in and signing out).
|
||||
* You likely only need to use this if you are not using the built-in
|
||||
* `signIn()` and `signOut()` methods.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#getcsrftoken)
|
||||
*/
|
||||
export async function getCsrfToken (params?: CtxOrReq) {
|
||||
const response = await fetchData<{ csrfToken: string }>(
|
||||
'csrf',
|
||||
__NEXTAUTH,
|
||||
logger,
|
||||
params
|
||||
)
|
||||
return response?.csrfToken
|
||||
}
|
||||
|
||||
/**
|
||||
* It calls `/api/auth/providers` and returns
|
||||
* a list of the currently configured authentication providers.
|
||||
* It can be useful if you are creating a dynamic custom sign in page.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#getproviders)
|
||||
*/
|
||||
export async function getProviders () {
|
||||
return await fetchData<
|
||||
Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider>
|
||||
>('providers', __NEXTAUTH, logger)
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side method to initiate a signin flow
|
||||
* or send the user to the signin page listing all possible providers.
|
||||
* Automatically adds the CSRF token to the request.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#signin)
|
||||
*/
|
||||
export async function signIn<
|
||||
P extends RedirectableProviderType | undefined = undefined,
|
||||
> (
|
||||
provider?: LiteralUnion<BuiltInProviderType>,
|
||||
options?: SignInOptions,
|
||||
authorizationParams?: SignInAuthorizationParams
|
||||
): Promise<
|
||||
P extends RedirectableProviderType ? SignInResponse | undefined : undefined
|
||||
> {
|
||||
const { callbackUrl = window.location.href, redirect = true } = options ?? {}
|
||||
|
||||
const baseUrl = apiBaseUrl(__NEXTAUTH)
|
||||
const providers = await getProviders()
|
||||
|
||||
if (!providers) {
|
||||
window.location.href = `${baseUrl}/error`
|
||||
return
|
||||
}
|
||||
|
||||
if (!provider || !(provider in providers)) {
|
||||
window.location.href = `${baseUrl}/signin?${new URLSearchParams({
|
||||
callbackUrl
|
||||
})}`
|
||||
return
|
||||
}
|
||||
|
||||
const isCredentials = providers[provider].type === 'credentials'
|
||||
const isEmail = providers[provider].type === 'email'
|
||||
const isSupportingReturn = isCredentials || isEmail
|
||||
|
||||
const signInUrl = `${baseUrl}/${
|
||||
isCredentials ? 'callback' : 'signin'
|
||||
}/${provider}`
|
||||
|
||||
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
|
||||
|
||||
const res = await fetch(_signInUrl, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
// @ts-expect-error: Internal
|
||||
body: new URLSearchParams({
|
||||
...options,
|
||||
csrfToken: await getCsrfToken(),
|
||||
callbackUrl,
|
||||
json: true
|
||||
})
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
|
||||
if (redirect || !isSupportingReturn) {
|
||||
const url = data.url ?? callbackUrl
|
||||
window.location.href = url
|
||||
// If url contains a hash, the browser does not reload the page. We reload manually
|
||||
if (url.includes('#')) { window.location.reload() }
|
||||
return
|
||||
}
|
||||
|
||||
const error = new URL(data.url).searchParams.get('error')
|
||||
|
||||
if (res.ok) { await __NEXTAUTH._getSession({ event: 'storage' }) }
|
||||
|
||||
return {
|
||||
error,
|
||||
status: res.status,
|
||||
ok: res.ok,
|
||||
url: error ? null : data.url
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the user out, by removing the session cookie.
|
||||
* Automatically adds the CSRF token to the request.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#signout)
|
||||
*/
|
||||
export async function signOut<R extends boolean = true> (
|
||||
options?: SignOutParams<R>
|
||||
): Promise<R extends true ? undefined : SignOutResponse> {
|
||||
const { callbackUrl = window.location.href } = options ?? {}
|
||||
const baseUrl = apiBaseUrl(__NEXTAUTH)
|
||||
const fetchOptions = {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
// @ts-expect-error: Internal
|
||||
body: new URLSearchParams({
|
||||
csrfToken: await getCsrfToken(),
|
||||
callbackUrl,
|
||||
json: true
|
||||
})
|
||||
}
|
||||
const res = await fetch(`${baseUrl}/signout`, fetchOptions)
|
||||
const data = await res.json()
|
||||
|
||||
broadcast.post({ event: 'session', data: { trigger: 'signout' } })
|
||||
|
||||
if (options?.redirect ?? true) {
|
||||
const url = data.url ?? callbackUrl
|
||||
window.location.href = url
|
||||
// If url contains a hash, the browser does not reload the page. We reload manually
|
||||
if (url.includes('#')) { window.location.reload() }
|
||||
// @ts-expect-error: Internal
|
||||
return
|
||||
}
|
||||
|
||||
await __NEXTAUTH._getSession({ event: 'storage' })
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export function SessionProviderPlugin (options: SessionProviderProps): Plugin {
|
||||
return {
|
||||
install (app) {
|
||||
const { basePath } = options
|
||||
|
||||
if (basePath) { __NEXTAUTH.basePath = basePath }
|
||||
|
||||
/**
|
||||
* If session was `null`, there was an attempt to fetch it,
|
||||
* but it failed, but we still treat it as a valid initial value.
|
||||
*/
|
||||
const hasInitialSession = options.session !== undefined
|
||||
|
||||
/** If session was passed, initialize as already synced */
|
||||
__NEXTAUTH._lastSync = hasInitialSession ? now() : 0
|
||||
|
||||
if (hasInitialSession) { __NEXTAUTH._session = options.session }
|
||||
|
||||
const session = ref(options.session)
|
||||
|
||||
/** If session was passed, initialize as not loading */
|
||||
const loading = ref(!hasInitialSession)
|
||||
|
||||
__NEXTAUTH._getSession = async ({ event } = {}) => {
|
||||
try {
|
||||
const storageEvent = event === 'storage'
|
||||
// We should always update if we don't have a client session yet
|
||||
// or if there are events from other tabs/windows
|
||||
if (storageEvent || __NEXTAUTH._session === undefined) {
|
||||
__NEXTAUTH._lastSync = now()
|
||||
__NEXTAUTH._session = await getSession({
|
||||
broadcast: !storageEvent
|
||||
})
|
||||
session.value = __NEXTAUTH._session
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
// If there is no time defined for when a session should be considered
|
||||
// stale, then it's okay to use the value we have until an event is
|
||||
// triggered which updates it
|
||||
!event ||
|
||||
// If the client doesn't have a session then we don't need to call
|
||||
// the server to check if it does (if they have signed in via another
|
||||
// tab or window that will come through as a "stroage" event
|
||||
// event anyway)
|
||||
__NEXTAUTH._session === null ||
|
||||
// Bail out early if the client session is not stale yet
|
||||
now() < __NEXTAUTH._lastSync
|
||||
) { return }
|
||||
|
||||
// An event or session staleness occurred, update the client session.
|
||||
__NEXTAUTH._lastSync = now()
|
||||
__NEXTAUTH._session = await getSession()
|
||||
session.value = __NEXTAUTH._session
|
||||
} catch (error) {
|
||||
logger.error('CLIENT_SESSION_ERROR', error as Error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
__NEXTAUTH._getSession()
|
||||
|
||||
const { refetchOnWindowFocus = true } = options
|
||||
|
||||
// Listen for when the page is visible, if the user switches tabs
|
||||
// and makes our tab visible again, re-fetch the session, but only if
|
||||
// this feature is not disabled.
|
||||
const visibilityHandler = () => {
|
||||
if (refetchOnWindowFocus && document.visibilityState === 'visible') { __NEXTAUTH._getSession({ event: 'visibilitychange' }) }
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', visibilityHandler, false)
|
||||
|
||||
const unsubscribeFromBroadcast = broadcast.receive(() =>
|
||||
__NEXTAUTH._getSession({ event: 'storage' })
|
||||
)
|
||||
|
||||
const { refetchInterval } = options
|
||||
let refetchIntervalTimer: NodeJS.Timer
|
||||
|
||||
if (refetchInterval) {
|
||||
refetchIntervalTimer = setInterval(() => {
|
||||
if (__NEXTAUTH._session) { __NEXTAUTH._getSession({ event: 'poll' }) }
|
||||
}, refetchInterval * 1000)
|
||||
}
|
||||
|
||||
const originalUnmount = app.unmount
|
||||
app.unmount = function nextAuthUnmount () {
|
||||
document.removeEventListener('visibilitychange', visibilityHandler, false)
|
||||
unsubscribeFromBroadcast?.()
|
||||
clearInterval(refetchIntervalTimer)
|
||||
__NEXTAUTH._lastSync = 0
|
||||
__NEXTAUTH._session = undefined
|
||||
__NEXTAUTH._getSession = () => {}
|
||||
originalUnmount()
|
||||
}
|
||||
|
||||
const status = computed(() => loading.value ? 'loading' : session.value ? 'authenticated' : 'unauthenticated')
|
||||
const value = reactive({
|
||||
data: session,
|
||||
status
|
||||
})
|
||||
|
||||
app.provide('SessionKey', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue Composable that gives you access
|
||||
* to the logged in user's session data.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#usesession)
|
||||
*/
|
||||
export function useSession (): {
|
||||
data: Ref<SessionProviderProps['session']>;
|
||||
status: Ref<string>;
|
||||
} {
|
||||
if (typeof window === 'undefined') {
|
||||
return {
|
||||
data: ref(null),
|
||||
status: ref('loading')
|
||||
}
|
||||
}
|
||||
|
||||
const value = inject<{
|
||||
data: SessionProviderProps['session']
|
||||
status: string
|
||||
}>('SessionKey')
|
||||
if (!value) {
|
||||
throw new Error('Could not resolve provided session value')
|
||||
}
|
||||
const { data, status } = toRefs(value)
|
||||
|
||||
return {
|
||||
data,
|
||||
status
|
||||
}
|
||||
}
|
||||
115
apps/playground-nuxt/src/runtime/lib/errors.ts
Normal file
115
apps/playground-nuxt/src/runtime/lib/errors.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { Adapter } from 'next-auth/adapters'
|
||||
import type { EventCallbacks, LoggerInstance } from 'next-auth'
|
||||
|
||||
/**
|
||||
* Same as the default `Error`, but it is JSON serializable.
|
||||
* @source https://iaincollins.medium.com/error-handling-in-javascript-a6172ccdf9af
|
||||
*/
|
||||
export class UnknownError extends Error {
|
||||
code: string
|
||||
constructor (error: Error | string) {
|
||||
super((error as Error)?.message ?? error)
|
||||
this.name = 'UnknownError'
|
||||
this.code = (error as any).code
|
||||
if (error instanceof Error) { this.stack = error.stack }
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
return {
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
stack: this.stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OAuthCallbackError extends UnknownError {
|
||||
name = 'OAuthCallbackError'
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when an Email address is already associated with an account
|
||||
* but the user is trying an OAuth account that is not linked to it.
|
||||
*/
|
||||
export class AccountNotLinkedError extends UnknownError {
|
||||
name = 'AccountNotLinkedError'
|
||||
}
|
||||
|
||||
export class MissingAPIRoute extends UnknownError {
|
||||
name = 'MissingAPIRouteError'
|
||||
code = 'MISSING_NEXTAUTH_API_ROUTE_ERROR'
|
||||
}
|
||||
|
||||
export class MissingSecret extends UnknownError {
|
||||
name = 'MissingSecretError'
|
||||
code = 'NO_SECRET'
|
||||
}
|
||||
|
||||
export class MissingAuthorize extends UnknownError {
|
||||
name = 'MissingAuthorizeError'
|
||||
code = 'CALLBACK_CREDENTIALS_HANDLER_ERROR'
|
||||
}
|
||||
|
||||
export class MissingAdapter extends UnknownError {
|
||||
name = 'MissingAdapterError'
|
||||
code = 'EMAIL_REQUIRES_ADAPTER_ERROR'
|
||||
}
|
||||
|
||||
export class UnsupportedStrategy extends UnknownError {
|
||||
name = 'UnsupportedStrategyError'
|
||||
code = 'CALLBACK_CREDENTIALS_JWT_ERROR'
|
||||
}
|
||||
|
||||
type Method = (...args: any[]) => Promise<any>
|
||||
|
||||
export function upperSnake (s: string) {
|
||||
return s.replace(/([A-Z])/g, '_$1').toUpperCase()
|
||||
}
|
||||
|
||||
export function capitalize (s: string) {
|
||||
return `${s[0].toUpperCase()}${s.slice(1)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an object of methods and adds error handling.
|
||||
*/
|
||||
export function eventsErrorHandler (
|
||||
methods: Partial<EventCallbacks>,
|
||||
logger: LoggerInstance
|
||||
): Partial<EventCallbacks> {
|
||||
return Object.keys(methods).reduce<any>((acc, name) => {
|
||||
acc[name] = async (...args: any[]) => {
|
||||
try {
|
||||
const method: Method = methods[name as keyof Method]
|
||||
return await method(...args)
|
||||
} catch (e) {
|
||||
logger.error(`${upperSnake(name)}_EVENT_ERROR`, e as Error)
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
/** Handles adapter induced errors. */
|
||||
export function adapterErrorHandler (
|
||||
adapter: Adapter | undefined,
|
||||
logger: LoggerInstance
|
||||
): Adapter | undefined {
|
||||
if (!adapter) { return }
|
||||
|
||||
return Object.keys(adapter).reduce<any>((acc, name) => {
|
||||
acc[name] = async (...args: any[]) => {
|
||||
try {
|
||||
logger.debug(`adapter_${name}`, { args })
|
||||
const method: Method = adapter[name as keyof Method]
|
||||
return await method(...args)
|
||||
} catch (error) {
|
||||
logger.error(`adapter_error_${name}`, error as Error)
|
||||
const e = new UnknownError(error as Error)
|
||||
e.name = `${capitalize(name)}Error`
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
113
apps/playground-nuxt/src/runtime/lib/logger.ts
Normal file
113
apps/playground-nuxt/src/runtime/lib/logger.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { UnknownError } from './errors'
|
||||
|
||||
// TODO: better typing
|
||||
/** Makes sure that error is always serializable */
|
||||
function formatError (o: unknown): unknown {
|
||||
if (o instanceof Error && !(o instanceof UnknownError)) { return { message: o.message, stack: o.stack, name: o.name } }
|
||||
|
||||
if (hasErrorProperty(o)) {
|
||||
o.error = formatError(o.error) as Error
|
||||
o.message = o.message ?? o.error.message
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
function hasErrorProperty (
|
||||
x: unknown
|
||||
): x is { error: Error; [key: string]: unknown } {
|
||||
return !!(x as any)?.error
|
||||
}
|
||||
|
||||
export type WarningCode =
|
||||
| 'NEXTAUTH_URL'
|
||||
| 'NO_SECRET'
|
||||
| 'TWITTER_OAUTH_2_BETA'
|
||||
| 'DEBUG_ENABLED'
|
||||
|
||||
/**
|
||||
* Override any of the methods, and the rest will use the default logger.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/configuration/options#logger)
|
||||
*/
|
||||
export interface LoggerInstance extends Record<string, Function> {
|
||||
warn: (code: WarningCode) => void
|
||||
error: (
|
||||
code: string,
|
||||
/**
|
||||
* Either an instance of (JSON serializable) Error
|
||||
* or an object that contains some debug information.
|
||||
* (Error is still available through `metadata.error`)
|
||||
*/
|
||||
metadata: Error | { error: Error; [key: string]: unknown }
|
||||
) => void
|
||||
debug: (code: string, metadata: unknown) => void
|
||||
}
|
||||
|
||||
const _logger: LoggerInstance = {
|
||||
error (code, metadata) {
|
||||
metadata = formatError(metadata) as Error
|
||||
console.error(
|
||||
`[next-auth][error][${code}]`,
|
||||
`\nhttps://next-auth.js.org/errors#${code.toLowerCase()}`,
|
||||
metadata.message,
|
||||
metadata
|
||||
)
|
||||
},
|
||||
warn (code) {
|
||||
console.warn(
|
||||
`[next-auth][warn][${code}]`,
|
||||
`\nhttps://next-auth.js.org/warnings#${code.toLowerCase()}`
|
||||
)
|
||||
},
|
||||
debug (code, metadata) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[next-auth][debug][${code}]`, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the built-in logger with user's implementation.
|
||||
* Any `undefined` level will use the default logger.
|
||||
*/
|
||||
export function setLogger (
|
||||
newLogger: Partial<LoggerInstance> = {},
|
||||
debug?: boolean
|
||||
) {
|
||||
// Turn off debug logging if `debug` isn't set to `true`
|
||||
if (!debug) { _logger.debug = () => {} }
|
||||
|
||||
if (newLogger.error) { _logger.error = newLogger.error }
|
||||
if (newLogger.warn) { _logger.warn = newLogger.warn }
|
||||
if (newLogger.debug) { _logger.debug = newLogger.debug }
|
||||
}
|
||||
|
||||
export default _logger
|
||||
|
||||
/** Serializes client-side log messages and sends them to the server */
|
||||
export function proxyLogger (
|
||||
logger: LoggerInstance = _logger,
|
||||
basePath?: string
|
||||
): LoggerInstance {
|
||||
try {
|
||||
if (typeof window === 'undefined') { return logger }
|
||||
|
||||
const clientLogger: Record<string, unknown> = {}
|
||||
for (const level in logger) {
|
||||
clientLogger[level] = (code: string, metadata: Error) => {
|
||||
_logger[level](code, metadata) // Logs to console
|
||||
|
||||
if (level === 'error') {
|
||||
metadata = formatError(metadata) as Error
|
||||
}(metadata as any).client = true
|
||||
const url = `${basePath}/_log`
|
||||
const body = new URLSearchParams({ level, code, ...(metadata as any) })
|
||||
if (navigator.sendBeacon) { return navigator.sendBeacon(url, body) }
|
||||
|
||||
return fetch(url, { method: 'POST', body, keepalive: true })
|
||||
}
|
||||
}
|
||||
return clientLogger as unknown as LoggerInstance
|
||||
} catch {
|
||||
return _logger
|
||||
}
|
||||
}
|
||||
34
apps/playground-nuxt/src/runtime/lib/parse-url.ts
Normal file
34
apps/playground-nuxt/src/runtime/lib/parse-url.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export interface InternalUrl {
|
||||
/** @default "http://localhost:3000" */
|
||||
origin: string
|
||||
/** @default "localhost:3000" */
|
||||
host: string
|
||||
/** @default "/api/auth" */
|
||||
path: string
|
||||
/** @default "http://localhost:3000/api/auth" */
|
||||
base: string
|
||||
/** @default "http://localhost:3000/api/auth" */
|
||||
toString: () => string
|
||||
}
|
||||
|
||||
/** Returns an `URL` like object to make requests/redirects from server-side */
|
||||
export default function parseUrl (url?: string): InternalUrl {
|
||||
const defaultUrl = new URL('http://localhost:3000/api/auth')
|
||||
|
||||
if (url && !url.startsWith('http')) { url = `https://${url}` }
|
||||
|
||||
const _url = new URL(url ?? defaultUrl)
|
||||
const path = (_url.pathname === '/' ? defaultUrl.pathname : _url.pathname)
|
||||
// Remove trailing slash
|
||||
.replace(/\/$/, '')
|
||||
|
||||
const base = `${_url.origin}${path}`
|
||||
|
||||
return {
|
||||
origin: _url.origin,
|
||||
host: _url.host,
|
||||
path,
|
||||
base,
|
||||
toString: () => base
|
||||
}
|
||||
}
|
||||
7
apps/playground-nuxt/src/runtime/plugin.client.ts
Normal file
7
apps/playground-nuxt/src/runtime/plugin.client.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// @ts-expect-error: Nuxt auto-import
|
||||
import { defineNuxtPlugin } from '#app'
|
||||
import { SessionProviderPlugin } from './client'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.vueApp.use(SessionProviderPlugin({}))
|
||||
})
|
||||
93
apps/playground-nuxt/src/runtime/server/handler.ts
Normal file
93
apps/playground-nuxt/src/runtime/server/handler.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { NextAuthAction, NextAuthOptions, Session } from 'next-auth'
|
||||
import type { RequestInternal } from 'next-auth/core'
|
||||
import { NextAuthHandler } from 'next-auth/core'
|
||||
import {
|
||||
appendHeader,
|
||||
defineEventHandler,
|
||||
isMethod,
|
||||
sendRedirect,
|
||||
setCookie,
|
||||
readBody,
|
||||
parseCookies,
|
||||
getQuery
|
||||
} from 'h3'
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
export function NextAuthNuxtHandler (options: NextAuthOptions) {
|
||||
return defineEventHandler(async (event) => {
|
||||
// Catch-all route params in Nuxt goes to the underscore property
|
||||
const nextauth = event.context.params._.split('/')
|
||||
|
||||
const req: RequestInternal | Request = {
|
||||
host: process.env.NEXTAUTH_URL,
|
||||
body: undefined,
|
||||
query: getQuery(event),
|
||||
headers: event.req.headers,
|
||||
method: event.req.method,
|
||||
cookies: parseCookies(event),
|
||||
action: nextauth[0] as NextAuthAction,
|
||||
providerId: nextauth[1],
|
||||
error: nextauth[1]
|
||||
}
|
||||
|
||||
if (isMethod(event, 'POST')) {
|
||||
req.body = await readBody(event)
|
||||
}
|
||||
|
||||
const response = await NextAuthHandler({
|
||||
req,
|
||||
options
|
||||
})
|
||||
|
||||
const { headers, cookies, body, redirect, status = 200 } = response
|
||||
event.res.statusCode = status
|
||||
|
||||
headers?.forEach((header) => {
|
||||
appendHeader(event, header.key, header.value)
|
||||
})
|
||||
|
||||
cookies?.forEach((cookie) => {
|
||||
setCookie(event, cookie.name, cookie.value, cookie.options)
|
||||
})
|
||||
|
||||
if (redirect) {
|
||||
if (isMethod(event, 'POST')) {
|
||||
const body = await readBody(event)
|
||||
if (body?.json !== 'true') { await sendRedirect(event, redirect, 302) }
|
||||
|
||||
return {
|
||||
url: redirect
|
||||
}
|
||||
} else {
|
||||
await sendRedirect(event, redirect, 302)
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
})
|
||||
}
|
||||
|
||||
export async function getServerSession (
|
||||
event: H3Event,
|
||||
options: NextAuthOptions
|
||||
): Promise<Session | null> {
|
||||
options.secret = process.env.NEXTAUTH_SECRET
|
||||
|
||||
const session = await NextAuthHandler<Session>({
|
||||
req: {
|
||||
host: process.env.NEXTAUTH_URL,
|
||||
action: 'session',
|
||||
method: 'GET',
|
||||
cookies: parseCookies(event),
|
||||
headers: event.req.headers
|
||||
},
|
||||
options
|
||||
})
|
||||
|
||||
const { body } = session
|
||||
|
||||
if (body && Object.keys(body).length) {
|
||||
return body
|
||||
}
|
||||
return null
|
||||
}
|
||||
78
apps/playground-nuxt/src/runtime/types.ts
Normal file
78
apps/playground-nuxt/src/runtime/types.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Session } from 'next-auth'
|
||||
import type { BuiltInProviderType, ProviderType } from 'next-auth/providers'
|
||||
|
||||
export interface UseSessionOptions<R extends boolean> {
|
||||
required: R
|
||||
/** Defaults to `signIn` */
|
||||
onUnauthenticated?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Util type that matches some strings literally, but allows any other string as well.
|
||||
* @source https://github.com/microsoft/TypeScript/issues/29729#issuecomment-832522611
|
||||
*/
|
||||
export type LiteralUnion<T extends U, U = string> =
|
||||
| T
|
||||
| (U & Record<never, never>)
|
||||
|
||||
export interface ClientSafeProvider {
|
||||
id: LiteralUnion<BuiltInProviderType>
|
||||
name: string
|
||||
type: ProviderType
|
||||
signinUrl: string
|
||||
callbackUrl: string
|
||||
}
|
||||
|
||||
export interface SignInOptions extends Record<string, unknown> {
|
||||
/**
|
||||
* Defaults to the current URL.
|
||||
* @docs https://next-auth.js.org/getting-started/client#specifying-a-callbackurl
|
||||
*/
|
||||
callbackUrl?: string
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option */
|
||||
redirect?: boolean
|
||||
}
|
||||
|
||||
export interface SignInResponse {
|
||||
error: string | undefined
|
||||
status: number
|
||||
ok: boolean
|
||||
url: string | null
|
||||
}
|
||||
|
||||
/** Match `inputType` of `new URLSearchParams(inputType)` */
|
||||
export type SignInAuthorizationParams =
|
||||
| string
|
||||
| string[][]
|
||||
| Record<string, string>
|
||||
| URLSearchParams
|
||||
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 */
|
||||
export interface SignOutResponse {
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface SignOutParams<R extends boolean = true> {
|
||||
/** @docs https://next-auth.js.org/getting-started/client#specifying-a-callbackurl-1 */
|
||||
callbackUrl?: string
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 */
|
||||
redirect?: R
|
||||
}
|
||||
|
||||
/** @docs: https://next-auth.js.org/getting-started/client#options */
|
||||
export interface SessionProviderProps {
|
||||
// children: React.ReactNode
|
||||
session?: Session | null
|
||||
baseUrl?: string
|
||||
basePath?: string
|
||||
/**
|
||||
* A time interval (in seconds) after which the session will be re-fetched.
|
||||
* If set to `0` (default), the session is not polled.
|
||||
*/
|
||||
refetchInterval?: number
|
||||
/**
|
||||
* `SessionProvider` automatically refetches the session when the user switches between windows.
|
||||
* This option activates this behaviour if set to `true` (default).
|
||||
*/
|
||||
refetchOnWindowFocus?: boolean
|
||||
}
|
||||
4
apps/playground-nuxt/tsconfig.json
Normal file
4
apps/playground-nuxt/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://v3.nuxtjs.org/concepts/typescript
|
||||
"extends": "./playground/.nuxt/tsconfig.json"
|
||||
}
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
"prettier",
|
||||
],
|
||||
plugins: ["svelte3", "@typescript-eslint"],
|
||||
ignorePatterns: ["*.cjs"],
|
||||
ignorePatterns: ["*.cjs", "build/**/*"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript"),
|
||||
|
||||
@@ -4,6 +4,15 @@ NextAuth.js is committed to bringing easy authentication to other frameworks. ht
|
||||
|
||||
SvelteKit support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like `@next-auth/sveltekit`
|
||||
|
||||
## Running this Demo
|
||||
|
||||
- Copy `.env.example` to `.env`
|
||||
- In `.env`, set `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`
|
||||
- See [https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app))
|
||||
- When creating the OAuth app, set "Homepage URL" to `http://localhost:5173` and Authorization callack URL to `http://localhost:5173/api/auth/callback/github`
|
||||
- In `.env`, set `NEXTAUTH_SECRET` to any random string
|
||||
- Build and run the application: `yarn build && yarn start`
|
||||
|
||||
## Existing Project
|
||||
|
||||
### Add API Route
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "HOST=127.0.0.1 PORT=5173 ORIGIN=http://localhost:5173 node ./build",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "1.0.0-next.66",
|
||||
"@sveltejs/kit": "1.0.0-next.443",
|
||||
"@sveltejs/adapter-auto": "^1.0.0-next.80",
|
||||
"@sveltejs/adapter-node": "1.0.0-next.96",
|
||||
"@sveltejs/kit": "1.0.0-next.511",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
||||
"@typescript-eslint/parser": "^5.35.1",
|
||||
@@ -27,7 +29,7 @@
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "~4.8.2",
|
||||
"vite": "^2.9.13"
|
||||
"vite": "^3.1.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,7 +6,9 @@ export const handle: Handle = async function handle({
|
||||
resolve,
|
||||
}): Promise<Response> {
|
||||
const session = await getServerSession(event.request, nextAuthOptions)
|
||||
event.locals.session = session
|
||||
if (session) {
|
||||
event.locals.session = session
|
||||
}
|
||||
|
||||
return resolve(event)
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
NEXTAUTH_SECRET,
|
||||
} from "$env/static/private"
|
||||
import { PUBLIC_NEXTAUTH_URL } from "$env/static/public"
|
||||
import getFormBody from "./utils/get-form-body"
|
||||
|
||||
// @ts-expect-error import is exported on .default during SSR
|
||||
const github = GithubProvider?.default || GithubProvider
|
||||
|
||||
export const options: NextAuthOptions = {
|
||||
@@ -24,9 +24,11 @@ export const options: NextAuthOptions = {
|
||||
],
|
||||
}
|
||||
|
||||
const toSvelteKitResponse = async (
|
||||
const toSvelteKitResponse = async <
|
||||
T extends string | any[] | Record<string, any>
|
||||
>(
|
||||
request: Request,
|
||||
nextAuthResponse: NextAuthResponse<unknown>
|
||||
nextAuthResponse: NextAuthResponse<T>
|
||||
): Promise<Response> => {
|
||||
const { cookies, redirect } = nextAuthResponse
|
||||
|
||||
@@ -50,14 +52,14 @@ const toSvelteKitResponse = async (
|
||||
let status = nextAuthResponse.status || 200
|
||||
|
||||
if (redirect) {
|
||||
let formData = null
|
||||
let formData: FormData | null = null
|
||||
try {
|
||||
formData = await request.formData()
|
||||
formData = getFormBody(formData)
|
||||
} catch {
|
||||
// no formData passed
|
||||
}
|
||||
if (formData?.json !== "true") {
|
||||
const { json } = Object.fromEntries(formData ?? [])
|
||||
if (json !== "true") {
|
||||
status = 302
|
||||
headers.set("Location", redirect)
|
||||
} else {
|
||||
@@ -79,17 +81,16 @@ const SKNextAuthHandler = async (
|
||||
options: NextAuthOptions
|
||||
): Promise<Response> => {
|
||||
const [action, provider] = params.nextauth!.split("/")
|
||||
let body = undefined
|
||||
let body: FormData | undefined
|
||||
try {
|
||||
body = await request.formData()
|
||||
body = getFormBody(body)
|
||||
} catch {
|
||||
// no formData passed
|
||||
}
|
||||
options.secret = NEXTAUTH_SECRET
|
||||
const req: RequestInternal = {
|
||||
host: PUBLIC_NEXTAUTH_URL,
|
||||
body,
|
||||
body: Object.fromEntries(body ?? []),
|
||||
query: Object.fromEntries(url.searchParams),
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
@@ -135,8 +136,8 @@ export const getServerSession = async (
|
||||
export const NextAuth = (
|
||||
options: NextAuthOptions
|
||||
): {
|
||||
GET: (event) => Promise<unknown>
|
||||
POST: (event) => Promise<unknown>
|
||||
GET: (event: ServerLoadEvent) => Promise<unknown>
|
||||
POST: (event: ServerLoadEvent) => Promise<unknown>
|
||||
} => ({
|
||||
GET: (event) => SKNextAuthHandler(event, options),
|
||||
POST: (event) => SKNextAuthHandler(event, options),
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// https://dev.to/danawoodman/getting-form-body-data-in-your-sveltekit-endpoints-4a85
|
||||
export default function getFormBody(
|
||||
body: FormData | null
|
||||
): Record<string, any> {
|
||||
if (!body) return {}
|
||||
|
||||
// @ts-expect-error: Entries property type missing
|
||||
return [...body.entries()].reduce((data, [k, v]) => {
|
||||
const value = v
|
||||
if (k in data)
|
||||
data[k] = Array.isArray(data[k]) ? [...data[k], value] : [data[k], value]
|
||||
else data[k] = value
|
||||
return data
|
||||
}, {})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import adapter from "@sveltejs/adapter-auto"
|
||||
import adapter from "@sveltejs/adapter-node" // or use https://github.com/sveltejs/kit/tree/master/packages/adapter-auto
|
||||
import preprocess from "svelte-preprocess"
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
@@ -6,14 +6,8 @@ const config = {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
// Override http methods in the Todo forms
|
||||
methodOverride: {
|
||||
allowed: ["PATCH", "DELETE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,19 @@
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@cloudflare/workers-types@^3.14.0":
|
||||
version "3.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-3.15.0.tgz#b8b17f923181c61220880aaa8ef30d75d59a1219"
|
||||
integrity sha512-meL/Afy5qdIsgfdnlbVfcYUh/YjHk23EWUvgmULf6iDrDbrBcd+fse2os3CC7rxSfScdP1OqJVTHgRSEjUm/Pw==
|
||||
version "3.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-3.16.0.tgz#011658ca3f9810373e0eb4a2b5d6cabe4848d8d6"
|
||||
integrity sha512-gaBUSaKS65mN3iKZEgichbXYEmAa/pXkc5Gbt+1BptYphdGkj09ggdsiE4w8g0F/uI1g36QaTKrzVnBAWMipvQ==
|
||||
|
||||
"@esbuild/linux-loong64@0.14.54":
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
|
||||
integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
|
||||
"@esbuild/android-arm@0.15.10":
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.10.tgz#a5f9432eb221afc243c321058ef25fe899886892"
|
||||
integrity sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==
|
||||
|
||||
"@esbuild/linux-loong64@0.15.10":
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz#78a42897c2cf8db9fd5f1811f7590393b77774c7"
|
||||
integrity sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==
|
||||
|
||||
"@eslint/eslintrc@^1.3.1":
|
||||
version "1.3.1"
|
||||
@@ -82,9 +87,9 @@
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.5":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
|
||||
integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
|
||||
integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
|
||||
dependencies:
|
||||
detect-libc "^2.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
@@ -127,6 +132,47 @@
|
||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
|
||||
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
|
||||
|
||||
"@rollup/plugin-commonjs@^22.0.1":
|
||||
version "22.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz#ee8ca8415cda30d383b4096aad5222435b4b69b6"
|
||||
integrity sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
commondir "^1.0.1"
|
||||
estree-walker "^2.0.1"
|
||||
glob "^7.1.6"
|
||||
is-reference "^1.2.1"
|
||||
magic-string "^0.25.7"
|
||||
resolve "^1.17.0"
|
||||
|
||||
"@rollup/plugin-json@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
|
||||
integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.0.8"
|
||||
|
||||
"@rollup/plugin-node-resolve@^14.1.0":
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-14.1.0.tgz#f2fa475405cd7fed6420bf438fe393f988a9bc96"
|
||||
integrity sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
"@types/resolve" "1.17.1"
|
||||
deepmerge "^4.2.2"
|
||||
is-builtin-module "^3.1.0"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
|
||||
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
|
||||
dependencies:
|
||||
"@types/estree" "0.0.39"
|
||||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@rollup/pluginutils@^4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||
@@ -135,77 +181,96 @@
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@sveltejs/adapter-auto@1.0.0-next.66":
|
||||
version "1.0.0-next.66"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.66.tgz#93a6de02a7a4ebef11160bf8d012ef349839656e"
|
||||
integrity sha512-p78AQaSDHkLS5EFGqCF2xrLHMjKxx6wTLUvnP26cu2llh/VV4NihQ0rheVNgPWL+tGZpVznhrUG8fWmJxPciug==
|
||||
"@sveltejs/adapter-auto@^1.0.0-next.80":
|
||||
version "1.0.0-next.80"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.80.tgz#15d331bbfca89cb39b719c3086d134cc1a7227b1"
|
||||
integrity sha512-352WoZr9fQgxJqgNENvxRr2gsA+wTF6V9AVaQaaatDYd3RVEBaXTYOOalFaRLSa25mRUJaLYP2aaliqczMl23g==
|
||||
dependencies:
|
||||
"@sveltejs/adapter-cloudflare" "1.0.0-next.32"
|
||||
"@sveltejs/adapter-netlify" "1.0.0-next.72"
|
||||
"@sveltejs/adapter-vercel" "1.0.0-next.68"
|
||||
"@sveltejs/adapter-cloudflare" "1.0.0-next.38"
|
||||
"@sveltejs/adapter-netlify" "1.0.0-next.78"
|
||||
"@sveltejs/adapter-vercel" "1.0.0-next.77"
|
||||
|
||||
"@sveltejs/adapter-cloudflare@1.0.0-next.32":
|
||||
version "1.0.0-next.32"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-1.0.0-next.32.tgz#2e164e50786cf50d907f79a1d9ec8e0ab72a99df"
|
||||
integrity sha512-tzkUsdQlBk9xUjcGUOBYos4HKaeaXvz9v4TQ1QS2yIHEtL5xvMEDPZ94/DB2gPL4LZCnYbdY2lsy5HCsoN0hkQ==
|
||||
"@sveltejs/adapter-cloudflare@1.0.0-next.38":
|
||||
version "1.0.0-next.38"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-1.0.0-next.38.tgz#b4c6e7314de79f2a3ab1d8e2f88274a8c224e325"
|
||||
integrity sha512-N6jdTomRZkdKlcNoguwYD7lpdXSt0beIyUJsp0MS/YLm/4gI83y698zFYInFKJ9t5e6DAnuEBSAXcg568z2oFA==
|
||||
dependencies:
|
||||
"@cloudflare/workers-types" "^3.14.0"
|
||||
esbuild "^0.14.48"
|
||||
esbuild "^0.15.7"
|
||||
worktop "0.8.0-next.14"
|
||||
|
||||
"@sveltejs/adapter-netlify@1.0.0-next.72":
|
||||
version "1.0.0-next.72"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.72.tgz#5fe42a4944de476baa089cdc7f525ae6037585c9"
|
||||
integrity sha512-g570hYAMkgrJfo/TRg3DZFmlR7bNFHECFPOMgc8R+f28ROap/nXA8ICbiSBF7+zJ5JXvJbqHGjERSsyhEq+59g==
|
||||
"@sveltejs/adapter-netlify@1.0.0-next.78":
|
||||
version "1.0.0-next.78"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.78.tgz#a18e750ac9d146afb308c527649f24c40b746d59"
|
||||
integrity sha512-Yyn/j/0QcLK3Db442ducLUZmyvkO74j7Gdcwu9xN0fQN3kBlCJP9Itx5o4SySrPFGc4Q8cLJ5ELNg+mWduLBAA==
|
||||
dependencies:
|
||||
"@iarna/toml" "^2.2.5"
|
||||
esbuild "^0.14.48"
|
||||
esbuild "^0.15.7"
|
||||
set-cookie-parser "^2.4.8"
|
||||
tiny-glob "^0.2.9"
|
||||
|
||||
"@sveltejs/adapter-vercel@1.0.0-next.68":
|
||||
version "1.0.0-next.68"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-vercel/-/adapter-vercel-1.0.0-next.68.tgz#ccd0707f02d8aff9185b373a484366d961f58753"
|
||||
integrity sha512-ImM+fDwGkVaf920Wzh284nfAfu/WoPXCpMwog0kveIODVgCozbpJY55fO860LccqdS0YDyeFqOUrZJCqcYNx4w==
|
||||
"@sveltejs/adapter-node@1.0.0-next.96":
|
||||
version "1.0.0-next.96"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.96.tgz#3f071a0677f787f9e8b2157b087b5403c4df4b6c"
|
||||
integrity sha512-tIHaRolUYy2PiHl4RUWaOsYxEjK5lN9501qzCzFbYr/uoLnZcnPGSXNJICwX0AX9AUkV6cvkZey6bLbUQcwH0Q==
|
||||
dependencies:
|
||||
"@vercel/nft" "^0.21.0"
|
||||
esbuild "^0.14.48"
|
||||
"@rollup/plugin-commonjs" "^22.0.1"
|
||||
"@rollup/plugin-json" "^4.1.0"
|
||||
"@rollup/plugin-node-resolve" "^14.1.0"
|
||||
rollup "^2.78.1"
|
||||
|
||||
"@sveltejs/kit@1.0.0-next.443":
|
||||
version "1.0.0-next.443"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-1.0.0-next.443.tgz#5797a3c21d839562b3e96d19151beefa957dbf37"
|
||||
integrity sha512-Stdjwj6iL/u40O/+20UKTWtCBYxYaKwX2nRV5devrGk5hvq6/FbAqw+azwoWKvNoz3PGtrSmHIyeLcAx8iKQcw==
|
||||
"@sveltejs/adapter-vercel@1.0.0-next.77":
|
||||
version "1.0.0-next.77"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-vercel/-/adapter-vercel-1.0.0-next.77.tgz#be9bfa2b46fd63723893d37ecdacbb1d735515c3"
|
||||
integrity sha512-r4MqtP+lzx83HfcvI8PU0Yxzmxt6WQq9nzZETLboJouJzhSBUFIN5RmNZfEn6nNIlUwZbGQUEK/FxsRnnxI/Ig==
|
||||
dependencies:
|
||||
"@sveltejs/vite-plugin-svelte" "^1.0.1"
|
||||
"@vercel/nft" "^0.22.0"
|
||||
esbuild "^0.15.7"
|
||||
|
||||
"@sveltejs/kit@1.0.0-next.511":
|
||||
version "1.0.0-next.511"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-1.0.0-next.511.tgz#d045d0737ec93d21de5a27b6ca619daf79f8e4f7"
|
||||
integrity sha512-A/fxd4qHWDD07Mjo6qEEEfsBEkoj5C4/dPSzx6xPUoWmPvRPhU8t+P0oMc8BOn5YHOhPDq3coH8bmafbh73zKg==
|
||||
dependencies:
|
||||
"@sveltejs/vite-plugin-svelte" "^1.0.5"
|
||||
"@types/cookie" "^0.5.1"
|
||||
cookie "^0.5.0"
|
||||
devalue "^2.0.1"
|
||||
devalue "^4.0.0"
|
||||
kleur "^4.1.4"
|
||||
magic-string "^0.26.2"
|
||||
mime "^3.0.0"
|
||||
node-fetch "^3.2.4"
|
||||
sade "^1.8.1"
|
||||
set-cookie-parser "^2.4.8"
|
||||
sirv "^2.0.2"
|
||||
tiny-glob "^0.2.9"
|
||||
undici "^5.8.1"
|
||||
undici "^5.11.0"
|
||||
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.3.tgz#f760677e03074b9f42335dbde33ba988c95d1e67"
|
||||
integrity sha512-0Qu51m2W9RBlxWPp8i31KJpnqmjWMOne8vAzgmOX6ZM9uX+/RAv6BNhEMcNoP5MsyLjyW1ZTCiJoaZZ5EeqpFg==
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.5":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.9.tgz#b19bde0ba1929a06205888e94475595e3ac0c258"
|
||||
integrity sha512-+SDrAnT7TDi8sdj4OfD2SC4s9DNrpNVBrue8fT2PmKks9Ddu0JIfSeX91wXZb/1xHz4EkGb+rli8GTRI0yGOjg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^4.2.1"
|
||||
debug "^4.3.4"
|
||||
deepmerge "^4.2.2"
|
||||
kleur "^4.1.5"
|
||||
magic-string "^0.26.2"
|
||||
svelte-hmr "^0.14.12"
|
||||
magic-string "^0.26.5"
|
||||
svelte-hmr "^0.15.0"
|
||||
|
||||
"@types/cookie@^0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554"
|
||||
integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==
|
||||
|
||||
"@types/estree@*":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
|
||||
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
|
||||
|
||||
"@types/estree@0.0.39":
|
||||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
|
||||
|
||||
"@types/json-schema@^7.0.9":
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
||||
@@ -221,6 +286,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.6.tgz#f830323c88172e66826d0bde413498b61054b5a6"
|
||||
integrity sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/sass@^1.16.0":
|
||||
version "1.43.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/sass/-/sass-1.43.1.tgz#86bb0168e9e881d7dade6eba16c9ed6d25dc2f68"
|
||||
@@ -309,10 +381,10 @@
|
||||
"@typescript-eslint/types" "5.36.1"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@vercel/nft@^0.21.0":
|
||||
version "0.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.21.0.tgz#e0715b1997cd7021a7c7c48b584ef2295fd4b810"
|
||||
integrity sha512-hFCAETfI5cG8l5iAiLhMC2bReC5K7SIybzrxGorv+eGspIbIFsVw7Vg85GovXm/LxA08pIDrAlrhR6GN36XB/Q==
|
||||
"@vercel/nft@^0.22.0":
|
||||
version "0.22.1"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.22.1.tgz#0d91d2a21e3a7f0b23ce1550da9870eac4942828"
|
||||
integrity sha512-lYYZIoxRurqDOSoVIdBicGnpUIpfyaS5qVjdPq+EfI285WqtZK3NK/dyCkiyBul+X2U2OEhRyeMdXPCHGJbohw==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||
acorn "^8.6.0"
|
||||
@@ -443,6 +515,18 @@ buffer-crc32@^0.2.5:
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
|
||||
builtin-modules@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
|
||||
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
||||
|
||||
busboy@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
|
||||
dependencies:
|
||||
streamsearch "^1.1.0"
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
@@ -493,6 +577,11 @@ color-support@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||
integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -522,11 +611,6 @@ cross-spawn@^7.0.2:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
||||
|
||||
debug@4, debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
@@ -566,10 +650,10 @@ detect-libc@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
|
||||
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
|
||||
|
||||
devalue@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/devalue/-/devalue-2.0.1.tgz#5d368f9adc0928e47b77eea53ca60d2f346f9762"
|
||||
integrity sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q==
|
||||
devalue@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/devalue/-/devalue-4.0.0.tgz#efeadbc922894d468ad903029d4a7e65e37f4952"
|
||||
integrity sha512-w25siwXyuMUqMr7jPlEjyNCp1vn0Jzj/fNg3qVt/r/Dpe8HjESh2V92L0jmh3uq4iJt0BvjH+Azk1pQzkcnDWA==
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
@@ -595,132 +679,133 @@ es6-promise@^3.1.2:
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
|
||||
integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=
|
||||
|
||||
esbuild-android-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||
esbuild-android-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz#8a59a84acbf2eca96996cadc35642cf055c494f0"
|
||||
integrity sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==
|
||||
|
||||
esbuild-android-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||
esbuild-android-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz#f453851dc1d8c5409a38cf7613a33852faf4915d"
|
||||
integrity sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==
|
||||
|
||||
esbuild-darwin-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||
esbuild-darwin-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz#778bd29c8186ff47b176c8af58c08cf0fb8e6b86"
|
||||
integrity sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==
|
||||
|
||||
esbuild-darwin-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||
esbuild-darwin-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz#b30bbefb46dc3c5d4708b0435e52f6456578d6df"
|
||||
integrity sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==
|
||||
|
||||
esbuild-freebsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||
esbuild-freebsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz#ab301c5f6ded5110dbdd611140bef1a7c2e99236"
|
||||
integrity sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==
|
||||
|
||||
esbuild-freebsd-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||
esbuild-freebsd-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz#a5b09b867a6ff49110f52343b6f12265db63d43f"
|
||||
integrity sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==
|
||||
|
||||
esbuild-linux-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||
esbuild-linux-32@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz#5282fe9915641caf9c8070e4ba2c3e16d358f837"
|
||||
integrity sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==
|
||||
|
||||
esbuild-linux-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||
esbuild-linux-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz#f3726e85a00149580cb19f8abfabcbb96f5d52bb"
|
||||
integrity sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==
|
||||
|
||||
esbuild-linux-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||
esbuild-linux-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz#2f0056e9d5286edb0185b56655caa8c574d8dbe7"
|
||||
integrity sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==
|
||||
|
||||
esbuild-linux-arm@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||
esbuild-linux-arm@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz#40a9270da3c8ffa32cf72e24a79883e323dff08d"
|
||||
integrity sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==
|
||||
|
||||
esbuild-linux-mips64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||
esbuild-linux-mips64le@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz#90ce1c4ee0202edb4ac69807dea77f7e5804abc4"
|
||||
integrity sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==
|
||||
|
||||
esbuild-linux-ppc64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||
esbuild-linux-ppc64le@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz#782837ae7bd5b279178106c9dd801755a21fabdf"
|
||||
integrity sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==
|
||||
|
||||
esbuild-linux-riscv64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||
esbuild-linux-riscv64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz#d7420d806ece5174f24f4634303146f915ab4207"
|
||||
integrity sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==
|
||||
|
||||
esbuild-linux-s390x@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||
esbuild-linux-s390x@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz#21fdf0cb3494a7fb520a71934e4dffce67fe47be"
|
||||
integrity sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==
|
||||
|
||||
esbuild-netbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||
esbuild-netbsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz#6c06b3107e3df53de381e6299184d4597db0440f"
|
||||
integrity sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==
|
||||
|
||||
esbuild-openbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||
esbuild-openbsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz#4daef5f5d8e74bbda53b65160029445d582570cf"
|
||||
integrity sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==
|
||||
|
||||
esbuild-sunos-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||
esbuild-sunos-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz#5fe7bef267a02f322fd249a8214d0274937388a7"
|
||||
integrity sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==
|
||||
|
||||
esbuild-windows-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||
integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
|
||||
esbuild-windows-32@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz#48e3dde25ab0135579a288b30ab6ddef6d1f0b28"
|
||||
integrity sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==
|
||||
|
||||
esbuild-windows-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
|
||||
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||
esbuild-windows-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz#387a9515bef3fee502d277a5d0a2db49a4ecda05"
|
||||
integrity sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==
|
||||
|
||||
esbuild-windows-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
|
||||
integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
|
||||
esbuild-windows-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz#5a6fcf2fa49e895949bf5495cf088ab1b43ae879"
|
||||
integrity sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==
|
||||
|
||||
esbuild@^0.14.27, esbuild@^0.14.48:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
|
||||
integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
|
||||
esbuild@^0.15.7, esbuild@^0.15.9:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.10.tgz#85c2f8446e9b1fe04fae68daceacba033eedbd42"
|
||||
integrity sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==
|
||||
optionalDependencies:
|
||||
"@esbuild/linux-loong64" "0.14.54"
|
||||
esbuild-android-64 "0.14.54"
|
||||
esbuild-android-arm64 "0.14.54"
|
||||
esbuild-darwin-64 "0.14.54"
|
||||
esbuild-darwin-arm64 "0.14.54"
|
||||
esbuild-freebsd-64 "0.14.54"
|
||||
esbuild-freebsd-arm64 "0.14.54"
|
||||
esbuild-linux-32 "0.14.54"
|
||||
esbuild-linux-64 "0.14.54"
|
||||
esbuild-linux-arm "0.14.54"
|
||||
esbuild-linux-arm64 "0.14.54"
|
||||
esbuild-linux-mips64le "0.14.54"
|
||||
esbuild-linux-ppc64le "0.14.54"
|
||||
esbuild-linux-riscv64 "0.14.54"
|
||||
esbuild-linux-s390x "0.14.54"
|
||||
esbuild-netbsd-64 "0.14.54"
|
||||
esbuild-openbsd-64 "0.14.54"
|
||||
esbuild-sunos-64 "0.14.54"
|
||||
esbuild-windows-32 "0.14.54"
|
||||
esbuild-windows-64 "0.14.54"
|
||||
esbuild-windows-arm64 "0.14.54"
|
||||
"@esbuild/android-arm" "0.15.10"
|
||||
"@esbuild/linux-loong64" "0.15.10"
|
||||
esbuild-android-64 "0.15.10"
|
||||
esbuild-android-arm64 "0.15.10"
|
||||
esbuild-darwin-64 "0.15.10"
|
||||
esbuild-darwin-arm64 "0.15.10"
|
||||
esbuild-freebsd-64 "0.15.10"
|
||||
esbuild-freebsd-arm64 "0.15.10"
|
||||
esbuild-linux-32 "0.15.10"
|
||||
esbuild-linux-64 "0.15.10"
|
||||
esbuild-linux-arm "0.15.10"
|
||||
esbuild-linux-arm64 "0.15.10"
|
||||
esbuild-linux-mips64le "0.15.10"
|
||||
esbuild-linux-ppc64le "0.15.10"
|
||||
esbuild-linux-riscv64 "0.15.10"
|
||||
esbuild-linux-s390x "0.15.10"
|
||||
esbuild-netbsd-64 "0.15.10"
|
||||
esbuild-openbsd-64 "0.15.10"
|
||||
esbuild-sunos-64 "0.15.10"
|
||||
esbuild-windows-32 "0.15.10"
|
||||
esbuild-windows-64 "0.15.10"
|
||||
esbuild-windows-arm64 "0.15.10"
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -858,6 +943,11 @@ estree-walker@^0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
|
||||
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
|
||||
|
||||
estree-walker@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
|
||||
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
@@ -896,14 +986,6 @@ fastq@^1.6.0:
|
||||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||
@@ -944,13 +1026,6 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
|
||||
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
@@ -1019,6 +1094,18 @@ glob@^7.1.3:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.1.6:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@^13.15.0:
|
||||
version "13.17.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
|
||||
@@ -1126,10 +1213,17 @@ is-binary-path@~2.1.0:
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-core-module@^2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
|
||||
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
|
||||
is-builtin-module@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.0.tgz#bb0310dfe881f144ca83f30100ceb10cf58835e0"
|
||||
integrity sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==
|
||||
dependencies:
|
||||
builtin-modules "^3.3.0"
|
||||
|
||||
is-core-module@^2.9.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
|
||||
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
@@ -1150,11 +1244,23 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
|
||||
integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-reference@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
|
||||
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -1233,6 +1339,13 @@ magic-string@^0.26.2:
|
||||
dependencies:
|
||||
sourcemap-codec "^1.4.8"
|
||||
|
||||
magic-string@^0.26.5:
|
||||
version "0.26.6"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.6.tgz#b61e417c9f40b7b53bf7e73c0a803258e20d25ee"
|
||||
integrity sha512-6d+3bFybzyQFJYSoRsl9ZC0wheze8M1LrQC7tNMRqXR4izUTDOLMd9BtSuExK9iAukFh+s5K0WAhc/dlQ+HKYA==
|
||||
dependencies:
|
||||
sourcemap-codec "^1.4.8"
|
||||
|
||||
make-dir@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
||||
@@ -1271,7 +1384,7 @@ min-indent@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
minimatch@^3.0.4, minimatch@^3.1.2:
|
||||
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
@@ -1350,11 +1463,6 @@ next-auth@latest:
|
||||
preact-render-to-string "^5.1.19"
|
||||
uuid "^8.3.2"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
@@ -1362,15 +1470,6 @@ node-fetch@^2.6.7:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^3.2.4:
|
||||
version "3.2.10"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8"
|
||||
integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-gyp-build@^4.2.2:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
|
||||
@@ -1503,10 +1602,10 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
postcss@^8.4.13:
|
||||
version "8.4.16"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||
postcss@^8.4.16:
|
||||
version "8.4.17"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.17.tgz#f87863ec7cd353f81f7ab2dec5d67d861bbb1be5"
|
||||
integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==
|
||||
dependencies:
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
@@ -1595,12 +1694,12 @@ resolve-from@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
||||
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
|
||||
|
||||
resolve@^1.22.0:
|
||||
version "1.22.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
|
||||
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
|
||||
resolve@^1.17.0, resolve@^1.19.0, resolve@^1.22.1:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
dependencies:
|
||||
is-core-module "^2.8.1"
|
||||
is-core-module "^2.9.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
@@ -1630,10 +1729,17 @@ rollup-pluginutils@^2.8.2:
|
||||
dependencies:
|
||||
estree-walker "^0.6.1"
|
||||
|
||||
rollup@^2.59.0:
|
||||
version "2.67.3"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.67.3.tgz#3f04391fc296f807d067c9081d173e0a33dbd37e"
|
||||
integrity sha512-G/x1vUwbGtP6O5ZM8/sWr8+p7YfZhI18pPqMRtMYMWSbHjKZ/ajHGiM+GWNTlWyOR0EHIdT8LHU+Z4ciIZ1oBw==
|
||||
rollup@^2.78.1:
|
||||
version "2.79.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
|
||||
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rollup@~2.78.0:
|
||||
version "2.78.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.78.1.tgz#52fe3934d9c83cb4f7c4cb5fb75d88591be8648f"
|
||||
integrity sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
@@ -1672,9 +1778,9 @@ semver@^6.0.0:
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
version "7.3.8"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
|
||||
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@@ -1746,6 +1852,11 @@ sourcemap-codec@^1.3.0, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
|
||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
@@ -1807,10 +1918,10 @@ svelte-check@^2.8.1:
|
||||
svelte-preprocess "^4.0.0"
|
||||
typescript "*"
|
||||
|
||||
svelte-hmr@^0.14.12:
|
||||
version "0.14.12"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.12.tgz#a127aec02f1896500b10148b2d4d21ddde39973f"
|
||||
integrity sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==
|
||||
svelte-hmr@^0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.0.tgz#c8304b5dd33f006415329d91470761d19417a324"
|
||||
integrity sha512-Aw21SsyoohyVn4yiKXWPNCSW2DQNH/76kvUnE9kpt4h9hcg9tfyQc6xshx9hzgMfGF0kVx0EGD8oBMWSnATeOg==
|
||||
|
||||
svelte-preprocess@^4.0.0:
|
||||
version "4.10.3"
|
||||
@@ -1922,10 +2033,12 @@ typescript@~4.8.2:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790"
|
||||
integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==
|
||||
|
||||
undici@^5.8.1:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-5.10.0.tgz#dd9391087a90ccfbd007568db458674232ebf014"
|
||||
integrity sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==
|
||||
undici@^5.11.0:
|
||||
version "5.11.0"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-5.11.0.tgz#1db25f285821828fc09d3804b9e2e934ae86fc13"
|
||||
integrity sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw==
|
||||
dependencies:
|
||||
busboy "^1.6.0"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
@@ -1944,23 +2057,18 @@ uuid@^8.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
vite@^2.9.13:
|
||||
version "2.9.13"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.13.tgz#859cb5d4c316c0d8c6ec9866045c0f7858ca6abc"
|
||||
integrity sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==
|
||||
vite@^3.1.0:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-3.1.6.tgz#4c6db3000326342c918204a42a130fb3ffed2414"
|
||||
integrity sha512-qMXIwnehvvcK5XfJiXQUiTxoYAEMKhM+jqCY6ZSTKFBKu1hJnAKEzP3AOcnTerI0cMZYAaJ4wpW1wiXLMDt4mA==
|
||||
dependencies:
|
||||
esbuild "^0.14.27"
|
||||
postcss "^8.4.13"
|
||||
resolve "^1.22.0"
|
||||
rollup "^2.59.0"
|
||||
esbuild "^0.15.9"
|
||||
postcss "^8.4.16"
|
||||
resolve "^1.22.1"
|
||||
rollup "~2.78.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
||||
@@ -15,26 +15,23 @@ The MongoDB adapter does not handle connections automatically, so you will have
|
||||
npm install next-auth @next-auth/mongodb-adapter mongodb
|
||||
```
|
||||
|
||||
2. Add `lib/mongodb.js`
|
||||
2. Add `lib/mongodb.ts`
|
||||
|
||||
```js
|
||||
```ts
|
||||
// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
|
||||
import { MongoClient } from "mongodb"
|
||||
|
||||
const uri = process.env.MONGODB_URI
|
||||
const options = {
|
||||
useUnifiedTopology: true,
|
||||
useNewUrlParser: true,
|
||||
}
|
||||
|
||||
let client
|
||||
let clientPromise
|
||||
import { MongoClient } from 'mongodb'
|
||||
|
||||
if (!process.env.MONGODB_URI) {
|
||||
throw new Error("Please add your Mongo URI to .env.local")
|
||||
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"')
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const uri = process.env.MONGODB_URI
|
||||
const options = {}
|
||||
|
||||
let client
|
||||
let clientPromise: Promise<MongoClient>
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// In development mode, use a global variable so that the value
|
||||
// is preserved across module reloads caused by HMR (Hot Module Replacement).
|
||||
if (!global._mongoClientPromise) {
|
||||
|
||||
@@ -11,6 +11,7 @@ When using a database, you can still use JWT for session handling for fast acces
|
||||
|
||||
We have a list of official adapters that are distributed as their own packages under the `@next-auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages).
|
||||
|
||||
- [`xata`](./xata)
|
||||
- [`prisma`](./prisma)
|
||||
- [`fauna`](./fauna)
|
||||
- [`dynamodb`](./dynamodb)
|
||||
@@ -20,6 +21,7 @@ We have a list of official adapters that are distributed as their own packages u
|
||||
- [`neo4j`](./neo4j)
|
||||
- [`typeorm-legacy`](./typeorm)
|
||||
- [`sequelize`](./sequelize)
|
||||
- [`supabase`](./supabase)
|
||||
- [`dgraph`](./dgraph)
|
||||
- [`upstash-redis`](./upstash-redis)
|
||||
|
||||
|
||||
@@ -14,9 +14,13 @@ npm install prisma --save-dev
|
||||
|
||||
Create a file with your Prisma Client:
|
||||
|
||||
```javascript title="lib/prismadb.js"
|
||||
```typescript title="lib/prismadb.ts"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
declare global {
|
||||
var prisma: PrismaClient | undefined
|
||||
}
|
||||
|
||||
const client = globalThis.prisma || new PrismaClient()
|
||||
if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
|
||||
|
||||
309
docs/docs/adapters/supabase.md
Normal file
309
docs/docs/adapters/supabase.md
Normal file
@@ -0,0 +1,309 @@
|
||||
---
|
||||
id: supabase
|
||||
title: Supabase
|
||||
---
|
||||
|
||||
# Supabase
|
||||
|
||||
This is the Supabase Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
|
||||
|
||||
:::note
|
||||
This adapter is developed by the community and not officially maintained or supported by Supabase. It uses the Supabase Database to store user and session data in a separate `next_auth` schema. It is a standalone Auth server that does not interface with Supabase Auth and therefore provides a different feature set.
|
||||
|
||||
If you’re looking for an officially maintained Auth server with additional features like [built-in email server](https://supabase.com/docs/guides/auth/auth-email#configure-email-settings?utm_source=next-auth-docs&medium=referral&campaign=next-auth), [phone auth](https://supabase.com/docs/guides/auth/auth-twilio?utm_source=next-auth-docs&medium=referral&campaign=next-auth), and [Multi Factor Authentication (MFA / 2FA)](https://supabase.com/contact/mfa?utm_source=next-auth-docs&medium=referral&campaign=next-auth), please use [Supabase Auth](https://supabase.com/auth) with the [Auth Helpers for Next.js](https://supabase.com/docs/guides/auth/auth-helpers/nextjs?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
|
||||
:::
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install `@supabase/supabase-js`, `next-auth` and `@next-auth/supabase-adapter`.
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install @supabase/supabase-js next-auth @next-auth/supabase-adapter
|
||||
```
|
||||
|
||||
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
export default NextAuth({
|
||||
// https://next-auth.js.org/configuration/providers
|
||||
providers: [...],
|
||||
adapter: SupabaseAdapter({
|
||||
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
}),
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
### Create the `next_auth` schema in Supabase
|
||||
|
||||
Setup your database as described in our main [schema](/adapters/models), by copying the SQL schema below in the Supabase [SQL Editor](https://app.supabase.com/project/_/sql).
|
||||
|
||||
Alternatively you can select the NextAuth Quickstart card on the [SQL Editor page](https://app.supabase.com/project/_/sql), or [create a migration with the Supabase CLI](https://supabase.com/docs/guides/cli/local-development#database-migrations?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
|
||||
|
||||
```sql
|
||||
--
|
||||
-- Name: next_auth; Type: SCHEMA;
|
||||
--
|
||||
CREATE SCHEMA next_auth;
|
||||
|
||||
GRANT USAGE ON SCHEMA next_auth TO service_role;
|
||||
GRANT ALL ON SCHEMA next_auth TO postgres;
|
||||
|
||||
--
|
||||
-- Create users table
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS next_auth.users
|
||||
(
|
||||
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||
name text,
|
||||
email text,
|
||||
"emailVerified" timestamp with time zone,
|
||||
image text,
|
||||
CONSTRAINT users_pkey PRIMARY KEY (id),
|
||||
CONSTRAINT email_unique UNIQUE (email)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE next_auth.users TO postgres;
|
||||
GRANT ALL ON TABLE next_auth.users TO service_role;
|
||||
|
||||
--- uid() function to be used in RLS policies
|
||||
CREATE FUNCTION next_auth.uid() RETURNS uuid
|
||||
LANGUAGE sql STABLE
|
||||
AS $$
|
||||
select
|
||||
coalesce(
|
||||
nullif(current_setting('request.jwt.claim.sub', true), ''),
|
||||
(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
|
||||
)::uuid
|
||||
$$;
|
||||
|
||||
--
|
||||
-- Create sessions table
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS next_auth.sessions
|
||||
(
|
||||
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||
expires timestamp with time zone NOT NULL,
|
||||
"sessionToken" text NOT NULL,
|
||||
"userId" uuid,
|
||||
CONSTRAINT sessions_pkey PRIMARY KEY (id),
|
||||
CONSTRAINT sessionToken_unique UNIQUE ("sessionToken"),
|
||||
CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId")
|
||||
REFERENCES next_auth.users (id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE next_auth.sessions TO postgres;
|
||||
GRANT ALL ON TABLE next_auth.sessions TO service_role;
|
||||
|
||||
--
|
||||
-- Create accounts table
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS next_auth.accounts
|
||||
(
|
||||
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||
type text NOT NULL,
|
||||
provider text NOT NULL,
|
||||
"providerAccountId" text NOT NULL,
|
||||
refresh_token text,
|
||||
access_token text,
|
||||
expires_at bigint,
|
||||
token_type text,
|
||||
scope text,
|
||||
id_token text,
|
||||
session_state text,
|
||||
oauth_token_secret text,
|
||||
oauth_token text,
|
||||
"userId" uuid,
|
||||
CONSTRAINT accounts_pkey PRIMARY KEY (id),
|
||||
CONSTRAINT provider_unique UNIQUE (provider, "providerAccountId"),
|
||||
CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId")
|
||||
REFERENCES next_auth.users (id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE next_auth.accounts TO postgres;
|
||||
GRANT ALL ON TABLE next_auth.accounts TO service_role;
|
||||
|
||||
--
|
||||
-- Create verification_tokens table
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS next_auth.verification_tokens
|
||||
(
|
||||
identifier text,
|
||||
token text,
|
||||
expires timestamp with time zone NOT NULL,
|
||||
CONSTRAINT verification_tokens_pkey PRIMARY KEY (token),
|
||||
CONSTRAINT token_unique UNIQUE (token),
|
||||
CONSTRAINT token_identifier_unique UNIQUE (token, identifier)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE next_auth.verification_tokens TO postgres;
|
||||
GRANT ALL ON TABLE next_auth.verification_tokens TO service_role;
|
||||
```
|
||||
|
||||
### Expose the `next_auth` schema in Supabase
|
||||
|
||||
Expose the `next_auth` schema via the Serverless API in the [API settings](https://app.supabase.com/project/_/settings/api) by adding `next_auth` to the "Exposed schemas" list.
|
||||
|
||||
When developing locally add `next_auth` to the `schemas` array in the `config.toml` file in the `supabase` folder that was generated by the [Supabase CLI](https://supabase.com/docs/guides/cli/local-development#initialize-your-project?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
|
||||
|
||||
## Enabling Row Level Security (RLS)
|
||||
|
||||
Postgres provides a powerful feature called [Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security?utm_source=next-auth-docs&medium=referral&campaign=next-auth) to limit access to data.
|
||||
|
||||
This works by sending a signed JWT to your [Supabase Serverless API](https://supabase.com/docs/guides/api?utm_source=next-auth-docs&medium=referral&campaign=next-auth). There is two steps to make this work with NextAuth:
|
||||
|
||||
### 1. Generate the Supabase `access_token` JWT in the session callback
|
||||
|
||||
To sign the JWT use the `jsonwebtoken` package:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install jsonwebtoken
|
||||
```
|
||||
|
||||
Using the [NexthAuth Session callback](https://next-auth.js.org/configuration/callbacks#session-callback) create the Supabase `access_token` and append it to the `session` object.
|
||||
|
||||
To sign the JWT use the Supabase JWT secret which can be found in the [API settings](https://app.supabase.com/project/_/settings/api)
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
import jwt from "jsonwebtoken"
|
||||
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
export default NextAuth({
|
||||
// https://next-auth.js.org/configuration/providers
|
||||
providers: [...],
|
||||
adapter: SupabaseAdapter({
|
||||
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
}),
|
||||
callbacks: {
|
||||
async session({ session, user }) {
|
||||
const signingSecret = process.env.SUPABASE_JWT_SECRET
|
||||
if (signingSecret) {
|
||||
const payload = {
|
||||
aud: "authenticated",
|
||||
exp: Math.floor(new Date(session.expires).getTime() / 1000),
|
||||
sub: user.id,
|
||||
email: user.email,
|
||||
role: "authenticated",
|
||||
}
|
||||
session.supabaseAccessToken = jwt.sign(payload, signingSecret)
|
||||
}
|
||||
return session
|
||||
},
|
||||
},
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Inject the Supabase `access_token` JWT into the Supabase Client
|
||||
|
||||
For example, given the following public schema:
|
||||
|
||||
```sql
|
||||
/**
|
||||
* USERS
|
||||
* Note: This table contains user data. Users should only be able to view and update their own data.
|
||||
*/
|
||||
create table users (
|
||||
-- UUID from next_auth.users
|
||||
id uuid not null primary key,
|
||||
name text,
|
||||
email text,
|
||||
image text,
|
||||
constraint "users_id_fkey" foreign key ("id")
|
||||
references next_auth.users (id) match simple
|
||||
on update no action
|
||||
on delete cascade -- if user is deleted in NextAuth they will also be deleted in our public table.
|
||||
);
|
||||
alter table users enable row level security;
|
||||
create policy "Can view own user data." on users for select using (next_auth.uid() = id);
|
||||
create policy "Can update own user data." on users for update using (next_auth.uid() = id);
|
||||
|
||||
/**
|
||||
* This trigger automatically creates a user entry when a new user signs up via NextAuth.
|
||||
*/
|
||||
create function public.handle_new_user()
|
||||
returns trigger as $$
|
||||
begin
|
||||
insert into public.users (id, name, email, image)
|
||||
values (new.id, new.name, new.email, new.image);
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer;
|
||||
create trigger on_auth_user_created
|
||||
after insert on next_auth.users
|
||||
for each row execute procedure public.handle_new_user();
|
||||
```
|
||||
|
||||
The `supabaseAccessToken` is now available on the `session` object and can be passed to the supabase-js client. This works in any environment: client-side, server-side (API routes, SSR), as well as in middleware edge functions!
|
||||
|
||||
```js
|
||||
// ...
|
||||
// Use `useSession()` or `unstable_getServerSession()` to get the NextAuth session.
|
||||
|
||||
const { supabaseAccessToken } = session
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
// Now you can query with RLS enabled.
|
||||
const { data, error } = await supabase.from("users").select("*")
|
||||
```
|
||||
|
||||
## Usage with TypeScript
|
||||
|
||||
You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion.
|
||||
|
||||
Creating a new supabase client object:
|
||||
|
||||
```tsx
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
import { Database } from "../database.types"
|
||||
|
||||
const supabase = createClient<Database>()
|
||||
```
|
||||
|
||||
### Extend the session type with the `supabaseAccessToken`
|
||||
|
||||
In order to extend the `session` object with the `supabaseAccessToken` we need to extend the `session` interface in a `types/next-auth.d.ts` file:
|
||||
|
||||
```ts title="types/next-auth.d.ts"
|
||||
import NextAuth, { DefaultSession } from "next-auth"
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||
*/
|
||||
interface Session {
|
||||
// A JWT which can be used as Authorization header with supabase-js for RLS.
|
||||
supabaseAccessToken?: string
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
} & DefaultSession["user"]
|
||||
}
|
||||
}
|
||||
```
|
||||
242
docs/docs/adapters/xata.md
Normal file
242
docs/docs/adapters/xata.md
Normal file
@@ -0,0 +1,242 @@
|
||||
---
|
||||
id: xata
|
||||
title: Xata
|
||||
---
|
||||
|
||||
# Xata
|
||||
|
||||
This adapter allows using next-auth with Xata as a database to store users, sessions, and more. The preferred way to create a Xata project and use Xata databases is using the [Xata Command Line Interface (CLI)](https://docs.xata.io/cli/getting-started). The CLI allows generating a `XataClient` that will help you work with Xata in a safe way, and that this adapter depends on.
|
||||
|
||||
<!-- @todo add GIFs -->
|
||||
|
||||
## Getting Started
|
||||
|
||||
Let's first make sure we have everything installed and configured. We're going to need:
|
||||
|
||||
- next-auth + adapter
|
||||
- the Xata CLI
|
||||
- to configure the CLI
|
||||
|
||||
We can do this like so:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
# Install next-auth + adapter
|
||||
npm install next-auth @next-auth/xata-adapter
|
||||
|
||||
# Install the Xata CLI globally if you don't already have it
|
||||
npm install --location=global @xata.io/cli
|
||||
|
||||
# Login
|
||||
xata auth login
|
||||
```
|
||||
|
||||
Now that we're ready, let's create a new Xata project using our next-auth schema that the Xata adapter can work with. To do that, copy and paste this schema file into your project's directory:
|
||||
|
||||
```json title="schema.json"
|
||||
{
|
||||
"formatVersion": "",
|
||||
"tables": [
|
||||
{
|
||||
"name": "nextauth_users",
|
||||
"columns": [
|
||||
{
|
||||
"name": "email",
|
||||
"type": "email"
|
||||
},
|
||||
{
|
||||
"name": "emailVerified",
|
||||
"type": "datetime"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_accounts",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "providerAccountId",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "refresh_token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "access_token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires_at",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"name": "token_type",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "scope",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "id_token",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "session_state",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_verificationTokens",
|
||||
"columns": [
|
||||
{
|
||||
"name": "identifier",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires",
|
||||
"type": "datetime"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_users_accounts",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_accounts"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_users_sessions",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_sessions"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_sessions",
|
||||
"columns": [
|
||||
{
|
||||
"name": "sessionToken",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires",
|
||||
"type": "datetime"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Now, run the following command:
|
||||
|
||||
```bash
|
||||
xata init --schema=./path/to/your/schema.json
|
||||
```
|
||||
|
||||
The CLI will walk you through a setup process where you choose a [workspace](https://docs.xata.io/concepts/workspaces) (kind of like a GitHub org or a Vercel team) and an appropriate database. We recommend using a fresh database for this, as we'll augment it with tables that next-auth needs.
|
||||
|
||||
Once you're done, you can continue using next-auth in your project as expected, like creating a `./pages/api/auth/[...nextauth]` route.
|
||||
|
||||
```typescript title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
const client = new XataClient()
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Now to Xata-fy this route, let's add the Xata client and adapter:
|
||||
|
||||
```diff
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
+import { XataAdapter } from "@next-auth/xata-adapter"
|
||||
+import { XataClient } from "../../../xata" // or wherever you've chosen to create the client
|
||||
|
||||
+const client = new XataClient()
|
||||
|
||||
export default NextAuth({
|
||||
+ adapter: XataAdapter(client),
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
This fully sets up your next-auth site to work with Xata.
|
||||
|
||||
## Contributing
|
||||
|
||||
This is an open-source project created by humans, and as such, might have a few issues. If you experience any of these, we recommend [opening issues](https://github.com/nextauthjs/next-auth/issues/new?assignees=&labels=triage&template=1_bug_framework.yml&title=Issue%20on%20Xata%20adapter&description=I%20experienced%20this%20issue:\n##%20Reproduction%20Steps:\n\n-) that can help us solve problems and build reliable software.
|
||||
@@ -112,15 +112,16 @@ Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`,
|
||||
- As with database persisted session expiry times, token expiry time is extended whenever a session is active.
|
||||
- The arguments _user_, _account_, _profile_ and _isNewUser_ are only passed the first time this callback is called on a new session, after the user signs in. In subsequent calls, only `token` will be available.
|
||||
|
||||
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and on if you are using a database or not. You can persist data such as User ID, OAuth Access Token in this token. To make it available in the browser, check out the [`session()` callback](#session-callback) as well.
|
||||
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and if you are using a database. You can persist data such as User ID, OAuth Access Token in this token, see the example below for `access_token` and `user.id`. To expose it on the client side, check out the [`session()` callback](#session-callback) as well.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
...
|
||||
callbacks: {
|
||||
async jwt({ token, account }) {
|
||||
// Persist the OAuth access_token to the token right after signin
|
||||
async jwt({ token, account, profile }) {
|
||||
// Persist the OAuth access_token and or the user id to the token right after signin
|
||||
if (account) {
|
||||
token.accessToken = account.access_token
|
||||
token.id = profile.id
|
||||
}
|
||||
return token
|
||||
}
|
||||
@@ -134,7 +135,7 @@ Use an if branch to check for the existence of parameters (apart from `token`).
|
||||
|
||||
## Session callback
|
||||
|
||||
The session callback is called whenever a session is checked. By default, only a subset of the token is returned for increased security. If you want to make something available you added to the token through the `jwt()` callback, you have to explicitly forward it here to make it available to the client.
|
||||
The session callback is called whenever a session is checked. By default, **only a subset of the token is returned for increased security**. If you want to make something available you added to the token (like `access_token` and `user.id` from above) via the `jwt()` callback, you have to explicitly forward it here to make it available to the client.
|
||||
|
||||
e.g. `getSession()`, `useSession()`, `/api/auth/session`
|
||||
|
||||
@@ -145,8 +146,10 @@ e.g. `getSession()`, `useSession()`, `/api/auth/session`
|
||||
...
|
||||
callbacks: {
|
||||
async session({ session, token, user }) {
|
||||
// Send properties to the client, like an access_token from a provider.
|
||||
// Send properties to the client, like an access_token and user id from a provider.
|
||||
session.accessToken = token.accessToken
|
||||
session.user.id = token.id
|
||||
|
||||
return session
|
||||
}
|
||||
}
|
||||
@@ -155,7 +158,7 @@ callbacks: {
|
||||
|
||||
:::tip
|
||||
When using JSON Web Tokens the `jwt()` callback is invoked before the `session()` callback, so anything you add to the
|
||||
JSON Web Token will be immediately available in the session callback, like for example an `access_token` from a provider.
|
||||
JSON Web Token will be immediately available in the session callback, like for example an `access_token` or `id` from a provider.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
@@ -24,7 +24,7 @@ export const authOptions: NextAuthOptions = {
|
||||
export default NextAuth(authOptions);
|
||||
```
|
||||
|
||||
In `getServerSideProps`:
|
||||
### In `getServerSideProps`:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
@@ -48,7 +48,8 @@ export async function getServerSideProps(context) {
|
||||
}
|
||||
}
|
||||
```
|
||||
In API routes:
|
||||
|
||||
### In API Routes:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
@@ -68,6 +69,23 @@ export async function handler(req, res) {
|
||||
}
|
||||
```
|
||||
|
||||
### In `app/` directory:
|
||||
|
||||
You can also use `unstable_getServerSession` in Next.js' server components:
|
||||
|
||||
```tsx
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
Currently, the underlying Next.js `cookies()` method does [only provides read access](https://beta.nextjs.org/docs/api-reference/cookies) to the request cookies. This means that the `expires` value is stripped away from `session` in Server Components. Furthermore, there is a hard expiry on sessions, after which the user will be required to sign in again. (The default expiry is 30 days).
|
||||
:::
|
||||
|
||||
## Middleware
|
||||
|
||||
You can use a Next.js Middleware with NextAuth.js to protect your site.
|
||||
|
||||
@@ -13,12 +13,12 @@ When deploying to production, set the `NEXTAUTH_URL` environment variable to the
|
||||
NEXTAUTH_URL=https://example.com
|
||||
```
|
||||
|
||||
If your Next.js application uses a custom base path, specify the route to the API endpoint in full. More informations about the usage of custom base path [here](/getting-started/client#custom-base-path).
|
||||
If your Next.js application uses a custom base path, specify the route to the API endpoint in full. More information about the usage of custom base path [here](/getting-started/client#custom-base-path).
|
||||
|
||||
_e.g. `NEXTAUTH_URL=https://example.com/custom-route/api/auth`_
|
||||
|
||||
:::tip
|
||||
When you're using a custom base path, you will need to pass the `basePath` page prop to the `<SessionProvider>`. More informations [here](/getting-started/client#custom-base-path).
|
||||
When you're using a custom base path, you will need to pass the `basePath` page prop to the `<SessionProvider>`. More information [here](/getting-started/client#custom-base-path).
|
||||
:::
|
||||
|
||||
:::note
|
||||
@@ -472,7 +472,8 @@ cookies: {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: useSecureCookies
|
||||
secure: useSecureCookies,
|
||||
maxAge: 900
|
||||
}
|
||||
},
|
||||
state: {
|
||||
@@ -482,6 +483,7 @@ cookies: {
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: useSecureCookies,
|
||||
maxAge: 900
|
||||
},
|
||||
},
|
||||
nonce: {
|
||||
|
||||
@@ -13,7 +13,7 @@ Adding support for signing in via email in addition to one or more OAuth service
|
||||
Configuration is similar to other providers, but the options are different:
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import EmailProvider from `next-auth/providers/email`
|
||||
import EmailProvider from "next-auth/providers/email"
|
||||
...
|
||||
providers: [
|
||||
EmailProvider({
|
||||
|
||||
@@ -83,7 +83,7 @@ TWITTER_SECRET=YOUR_TWITTER_CLIENT_SECRET
|
||||
4. Now you can add the provider settings to the NextAuth.js options object. You can add as many OAuth providers as you like, as you can see `providers` is an array.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import TwitterProvider from "next-auth/providers/"
|
||||
import TwitterProvider from "next-auth/providers/twitter"
|
||||
...
|
||||
providers: [
|
||||
TwitterProvider({
|
||||
@@ -156,7 +156,7 @@ interface OAuthConfig {
|
||||
*/
|
||||
id: string
|
||||
version: string
|
||||
profile(profile: P, tokens: TokenSet): Awaitable<User & { id: string }>
|
||||
profile(profile: P, tokens: TokenSet): Awaitable<User>
|
||||
checks?: ChecksType | ChecksType[]
|
||||
clientId: string
|
||||
clientSecret: string
|
||||
@@ -173,6 +173,11 @@ interface OAuthConfig {
|
||||
region?: string
|
||||
issuer?: string
|
||||
client?: Partial<ClientMetadata>
|
||||
allowDangerousEmailAccountLinking?: boolean
|
||||
/**
|
||||
* Object containing the settings for the styling of the providers sign-in buttons
|
||||
*/
|
||||
style: ProviderStyleType
|
||||
}
|
||||
```
|
||||
|
||||
@@ -278,6 +283,10 @@ If your Provider is OpenID Connect (OIDC) compliant, we recommend using the `wel
|
||||
|
||||
An advanced option, hopefully you won't need it in most cases. `next-auth` uses `openid-client` under the hood, see the docs on this option [here](https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-clientmetadata-jwks-options).
|
||||
|
||||
### `allowDangerousEmailAccountLinking` option
|
||||
|
||||
Normally, when you sign in with an OAuth provider and another account with the same email address already exists, the accounts are not linked automatically. Automatic account linking on sign in is not secure between arbitrary providers and is disabled by default (see our [Security FAQ](https://next-auth.js.org/faq#security)). However, it may be desirable to allow automatic account linking if you trust that the provider involved has securely verified the email address associated with the account. Just set `allowDangerousEmailAccountLinking: true` in your provider configuration to enable automatic account linking.
|
||||
|
||||
## Using a custom provider
|
||||
|
||||
You can use an OAuth provider that isn't built-in by using a custom object.
|
||||
@@ -404,14 +413,28 @@ GoogleProvider({
|
||||
})
|
||||
```
|
||||
|
||||
An example of how to enable automatic account linking:
|
||||
|
||||
```js title=/api/auth/[...nextauth].js
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
})
|
||||
```
|
||||
|
||||
### Adding a new built-in provider
|
||||
|
||||
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily!
|
||||
|
||||
You only need to add two changes:
|
||||
You only need to add three changes:
|
||||
|
||||
1. Add your config: [`src/providers/{provider}.ts`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers)<br />
|
||||
• make sure you use a named default export, like this: `export default function YourProvider`
|
||||
- Make sure you use a named default export, like this: `export default function YourProvider`
|
||||
- Add two SVG's of the provider logo, like `google-dark.svg` (dark mode) and `google.svg` (light mode), to the `/packages/next-auth/provider-logos/` directory as well as the styling config to the provider config object. See existing provider for example
|
||||
2. Add provider documentation: [`/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/docs/docs/providers)
|
||||
3. Add the new provider name to the `Provider type` dropdown options in [`the provider issue template`](<[http](https://github.com/nextauthjs/next-auth/edit/main/.github/ISSUE_TEMPLATE/2_bug_provider.yml)>)
|
||||
|
||||
That's it! 🎉 Others will be able to discover and use this provider much more easily now!
|
||||
|
||||
@@ -136,7 +136,7 @@ The `callbackUrl` provided was either invalid or not defined. See [specifying a
|
||||
|
||||
#### JWT_SESSION_ERROR
|
||||
|
||||
JWKKeySupport: the key does not support HS512 verify algorithm
|
||||
JWTKeySupport: the key does not support HS512 verify algorithm
|
||||
|
||||
The algorithm used for generating your key isn't listed as supported. You can generate a HS512 key using
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function Component() {
|
||||
`useSession()` returns an object containing two values: `data` and `status`:
|
||||
|
||||
- **`data`**: This can be three values: [`Session`](https://github.com/nextauthjs/next-auth/blob/8ff4b260143458c5d8a16b80b11d1b93baa0690f/types/index.d.ts#L437-L444) / `undefined` / `null`.
|
||||
- when the session hasn't been fetched yet, `data` will `undefined`
|
||||
- when the session hasn't been fetched yet, `data` will be `undefined`
|
||||
- in case it failed to retrieve the session, `data` will be `null`
|
||||
- in case of success, `data` will be [`Session`](https://github.com/nextauthjs/next-auth/blob/8ff4b260143458c5d8a16b80b11d1b93baa0690f/types/index.d.ts#L437-L444).
|
||||
- **`status`**: enum mapping to three possible session states: `"loading" | "authenticated" | "unauthenticated"`
|
||||
@@ -290,7 +290,7 @@ export default ({ email }) => (
|
||||
|
||||
### Specifying a `callbackUrl`
|
||||
|
||||
The `callbackUrl` specifies to which URL the user will be redirected after signing in. It defaults to the current URL of a user.
|
||||
The `callbackUrl` specifies to which URL the user will be redirected after signing in. Defaults to the page URL the sign-in is initiated from.
|
||||
|
||||
You can specify a different `callbackUrl` by specifying it as the second argument of `signIn()`. This works for all providers.
|
||||
|
||||
@@ -491,6 +491,8 @@ If set to any value other than zero, it specifies in seconds how often the clien
|
||||
|
||||
The value for `refetchInterval` should always be lower than the value of the session `maxAge` [session option](/configuration/options#session).
|
||||
|
||||
By default, session polling will keep trying, even when the device has no internet access. To circumvent this, you can also set `refetchWhenOffline` to `false`. This will use [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) to only poll when the device is online.
|
||||
|
||||
#### Refetch On Window Focus
|
||||
|
||||
The `refetchOnWindowFocus` option can be used to control whether it automatically updates the session state when you switch a focus on tabs/windows.
|
||||
|
||||
@@ -7,11 +7,8 @@ title: Guides
|
||||
|
||||
We have internal guides in three levels of difficulty.
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
- [Basics](/guides/basics)
|
||||
- [Fullstack](/guides/fullstack)
|
||||
- [Testing](/guides/testing)
|
||||
|
||||
If you can't find what you're looking for here, maybe take a look at our third-party [tutorials](/tutorials) page.
|
||||
|
||||
@@ -44,17 +44,17 @@ providers: [
|
||||
CredentialsProvider({
|
||||
// The name to display on the sign in form (e.g. "Sign in with...")
|
||||
name: "Credentials",
|
||||
// The credentials is used to generate a suitable form on the sign in page.
|
||||
// You can specify whatever fields you are expecting to be submitted.
|
||||
// `credentials` is used to generate a form on the sign in page.
|
||||
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
|
||||
// e.g. domain, username, password, 2FA token, etc.
|
||||
// You can pass any HTML attribute to the <input> tag through the object.
|
||||
credentials: {
|
||||
username: { label: "Username", type: "text", placeholder: "jsmith" },
|
||||
password: { label: "Password", type: "password" }
|
||||
password: { label: "Password", type: "password" }
|
||||
},
|
||||
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" }
|
||||
const user = { id: "1", name: "J Smith", email: "jsmith@example.com" }
|
||||
|
||||
if (user) {
|
||||
// Any object returned will be saved in `user` property of the JWT
|
||||
|
||||
@@ -15,6 +15,7 @@ The Email provider can be used in conjunction with (or instead of) one or more O
|
||||
|
||||
On initial sign in, a **Verification Token** is sent to the email address provided. By default this token is valid for 24 hours. If the Verification Token is used within that time (i.e. by clicking on the link in the email) an account is created for the user and they are signed in.
|
||||
|
||||
|
||||
If someone provides the email address of an _existing account_ when signing in, an email is sent and they are signed into the account associated with that email address when they follow the link in the email.
|
||||
|
||||
:::tip
|
||||
@@ -32,7 +33,7 @@ You can override any of the options to suit your own use case.
|
||||
## Configuration
|
||||
|
||||
1. NextAuth.js does not include `nodemailer` as a dependency, so you'll need to install it yourself if you want to use the Email Provider. Run `npm install nodemailer` or `yarn add nodemailer`.
|
||||
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](http://nodemailer.com/smtp/well-known/).
|
||||
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services/).
|
||||
3. There are two ways to configure the SMTP server connection.
|
||||
|
||||
You can either use a connection string or a `nodemailer` configuration object.
|
||||
@@ -250,4 +251,4 @@ By default, NextAuth.js will normalize the email address. It treats values as ca
|
||||
|
||||
:::warning
|
||||
Always make sure this returns a single e-mail address, even if multiple ones were passed in.
|
||||
:::
|
||||
:::
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user