Compare commits

...

7 Commits

Author SHA1 Message Date
Balázs Orbán
b57dea40e2 chore: don't run build before tests 2022-12-23 03:09:39 +01:00
Balázs Orbán
1387445600 chore: more formatting 2022-12-23 03:03:52 +01:00
Balázs Orbán
b2d7f5529f chore: format 2022-12-23 03:02:26 +01:00
Balázs Orbán
7c101f5a73 chore: add auth packages as docs dependency 2022-12-23 02:56:02 +01:00
Balázs Orbán
92c96a267f chore: format 2022-12-23 02:50:00 +01:00
Balázs Orbán
b31bad15fe feat(sveltekit): update to use latest @auth/core 2022-12-23 02:38:36 +01:00
Balázs Orbán
d225bbe600 docs(sveltekit): autogenerate API reference 2022-12-23 02:37:43 +01:00
25 changed files with 339 additions and 392 deletions

View File

@@ -5,7 +5,7 @@ const path = require("path")
module.exports = { module.exports = {
root: true, root: true,
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
extends: ["standard-with-typescript", "prettier/prettier"], extends: ["standard-with-typescript", "prettier"],
rules: { rules: {
camelcase: "off", camelcase: "off",
"@typescript-eslint/naming-convention": "off", "@typescript-eslint/naming-convention": "off",

View File

@@ -29,8 +29,6 @@ jobs:
cache: "pnpm" cache: "pnpm"
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install
- name: Build
run: pnpm build
- name: Run tests - name: Run tests
run: pnpm test run: pnpm test
env: env:

1
.gitignore vendored
View File

@@ -87,6 +87,7 @@ packages/core/*.d.ts.map
packages/core/lib packages/core/lib
packages/core/providers packages/core/providers
docs/docs/reference/03-core docs/docs/reference/03-core
docs/docs/reference/04-sveltekit
# SvelteKit # SvelteKit

View File

@@ -6,10 +6,11 @@ module.exports = {
singleQuote: false, singleQuote: false,
overrides: [ overrides: [
{ {
files: "apps/dev/pages/api/auth/[...nextauth].ts", files: [
options: { "apps/dev/pages/api/auth/[...nextauth].ts",
printWidth: 150, "docs/{sidebars,docusaurus.config}.js",
}, ],
options: { printWidth: 150 },
}, },
], ],
} }

View File

@@ -1,60 +0,0 @@
---
title: SvelteKit Auth
---
:::warning
`@auth/sveltekit` is currently experimental.
:::
## Installation
```bash npm2yarn2pnpm
npm install @auth/core @auth/sveltekit
```
## Usage
Learn more about `@auth/sveltekit` [here](https://vercel.com/blog/announcing-sveltekit-auth)
```ts title="src/hooks.server.ts"
import SvelteKitAuth from "@auth/sveltekit"
import GitHub from "@auth/core/providers/github"
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
export const handle = SvelteKitAuth({
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
})
```
Don't forget to set the `AUTH_SECRET` [environment variable](https://kit.svelte.dev/docs/modules#$env-static-private). This should be a random 32 character string. On unix systems you can use `openssl rand -hex 32` or check out `https://generate-secret.vercel.app/32`.
When deploying your app outside Vercel, set the `AUTH_TRUST_HOST` variable to `true` for other hosting providers like Cloudflare Pages or Netlify.
## Signing in and signing out
```ts
<script>
import { signIn, signOut } from "@auth/sveltekit/client"
import { page } from "$app/stores"
</script>
<h1>SvelteKit Auth Example</h1>
<p>
{#if $page.data.session}
{#if $page.data.session.user?.image}
<span
style="background-image: url('{$page.data.session.user.image}')"
class="avatar"
/>
{/if}
<span class="signedInText">
<small>Signed in as</small><br />
<strong>{$page.data.session.user?.name ?? "User"}</strong>
</span>
<button on:click={() => signOut()} class="button">Sign out</button>
{:else}
<span class="notSignedInText">You are not signed in</span>
<button on:click={() => signIn("github")}>Sign In with GitHub</button>
{/if}
</p>
```

View File

@@ -179,10 +179,7 @@ const docusaurusConfig = {
lastVersion: "current", lastVersion: "current",
showLastUpdateAuthor: true, showLastUpdateAuthor: true,
showLastUpdateTime: true, showLastUpdateTime: true,
remarkPlugins: [ remarkPlugins: [require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm, require("remark-github")],
require("@sapphire/docusaurus-plugin-npm2yarn2pnpm").npm2yarn2pnpm,
require("remark-github"),
],
versions: { versions: {
current: { current: {
label: "experimental", label: "experimental",
@@ -200,95 +197,42 @@ const docusaurusConfig = {
"docusaurus-plugin-typedoc", "docusaurus-plugin-typedoc",
{ {
...typedocConfig, ...typedocConfig,
id: "core",
plugin: ["./tyepdoc"], plugin: ["./tyepdoc"],
entryPoints: [ entryPoints: ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"].map((e) => `${coreSrc}/${e}`).concat(providers),
"index.ts",
"adapters.ts",
"errors.ts",
"jwt.ts",
"types.ts",
]
.map((e) => `${coreSrc}/${e}`)
.concat(providers),
tsconfig: "../packages/core/tsconfig.json", tsconfig: "../packages/core/tsconfig.json",
out: "reference/03-core", out: "reference/03-core",
watch: process.env.TYPEDOC_WATCH, watch: process.env.TYPEDOC_WATCH,
includeExtension: false, includeExtension: false,
}, },
], ],
[
"docusaurus-plugin-typedoc",
{
...typedocConfig,
id: "sveltekit",
plugin: ["./tyepdoc"],
entryPoints: ["index.ts", "client.ts"].map((e) => `../packages/frameworks-sveltekit/src/lib/${e}`),
tsconfig: "../packages/frameworks-sveltekit/tsconfig.json",
out: "reference/04-sveltekit",
watch: process.env.TYPEDOC_WATCH,
includeExtension: false,
},
],
], ],
} }
docusaurusConfig.headTags = [ docusaurusConfig.headTags = [
{ { tagName: "meta", attributes: { charSet: "utf-8" } },
tagName: "meta", { tagName: "link", attributes: { rel: "canonical", href: docusaurusConfig.url } },
attributes: { { tagName: "meta", attributes: { property: "og:title", content: docusaurusConfig.title } },
charSet: "utf-8", { tagName: "meta", attributes: { property: "og:description", content: docusaurusConfig.tagline } },
}, { tagName: "meta", attributes: { property: "og:image", content: `${docusaurusConfig.url}/img/og-image.png` } },
}, { tagName: "meta", attributes: { property: "og:url", content: docusaurusConfig.url } },
{ { tagName: "meta", attributes: { name: "twitter:card", content: "summary_large_image" } },
tagName: "link", { tagName: "meta", attributes: { name: "twitter:title", content: docusaurusConfig.title } },
attributes: { { tagName: "meta", attributes: { name: "twitter:description", content: docusaurusConfig.tagline } },
rel: "canonical", { tagName: "meta", attributes: { name: "twitter:image", content: `${docusaurusConfig.url}/img/og-image.png` } },
href: docusaurusConfig.url,
},
},
{
tagName: "meta",
attributes: {
property: "og:title",
content: docusaurusConfig.title,
},
},
{
tagName: "meta",
attributes: {
property: "og:description",
content: docusaurusConfig.tagline,
},
},
{
tagName: "meta",
attributes: {
property: "og:image",
content: `${docusaurusConfig.url}/img/og-image.png`,
},
},
{
tagName: "meta",
attributes: {
property: "og:url",
content: docusaurusConfig.url,
},
},
{
tagName: "meta",
attributes: {
name: "twitter:card",
content: "summary_large_image",
},
},
{
tagName: "meta",
attributes: {
name: "twitter:title",
content: docusaurusConfig.title,
},
},
{
tagName: "meta",
attributes: {
name: "twitter:description",
content: docusaurusConfig.tagline,
},
},
{
tagName: "meta",
attributes: {
name: "twitter:image",
content: `${docusaurusConfig.url}/img/og-image.png`,
},
},
] ]
module.exports = docusaurusConfig module.exports = docusaurusConfig

View File

@@ -17,6 +17,8 @@
"snippets": "node ./scripts/generate-snippets" "snippets": "node ./scripts/generate-snippets"
}, },
"dependencies": { "dependencies": {
"@auth/core": "workspace:*",
"@auth/sveltekit": "workspace:*",
"@mdx-js/react": "1.6.22", "@mdx-js/react": "1.6.22",
"@sapphire/docusaurus-plugin-npm2yarn2pnpm": "1.1.4", "@sapphire/docusaurus-plugin-npm2yarn2pnpm": "1.1.4",
"classnames": "^2.3.2", "classnames": "^2.3.2",

View File

@@ -34,16 +34,22 @@ module.exports = {
label: "Reflections", label: "Reflections",
collapsed: true, collapsed: true,
className: "reflection-category", // See src/index.css className: "reflection-category", // See src/index.css
items: [ items: [{ type: "autogenerated", dirName: "reference/03-core" }],
{ },
type: "autogenerated", ],
dirName: "reference/03-core/functions", },
}, {
{ type: "category",
type: "autogenerated", label: "@auth/sveltekit",
dirName: "reference/03-core/interfaces", link: { type: "doc", id: "reference/sveltekit/modules/main" },
}, items: [
], { type: "autogenerated", dirName: "reference/04-sveltekit/modules" },
{
type: "category",
label: "Reflections",
collapsed: true,
className: "reflection-category", // See src/index.css
items: [{ type: "autogenerated", dirName: "reference/04-sveltekit" }],
}, },
], ],
}, },
@@ -63,30 +69,18 @@ module.exports = {
}, },
], ],
}, },
{
type: "category",
label: "@auth/sveltekit",
link: {
type: "doc",
id: "reference/sveltekit/index",
},
items: [],
},
{ {
type: "category", type: "category",
label: "Database Adapters", label: "Database Adapters",
link: { link: { type: "doc", id: "reference/adapters/overview" },
type: "doc",
id: "reference/adapters/overview",
},
items: [ items: [
{ {
type: "autogenerated", type: "autogenerated",
dirName: "reference/06-adapters", dirName: "reference/06-adapters",
// See: https://github.com/facebook/docusaurus/issues/5689 // See: https://github.com/facebook/docusaurus/issues/5689
// exclude: ["index"], // exclude: ["index"],
} },
] ],
}, },
{ {
type: "category", type: "category",
@@ -97,8 +91,8 @@ module.exports = {
dirName: "reference/05-oauth-providers", dirName: "reference/05-oauth-providers",
// See: https://github.com/facebook/docusaurus/issues/5689 // See: https://github.com/facebook/docusaurus/issues/5689
// exclude: ["index"], // exclude: ["index"],
} },
] ],
}, },
"reference/utilities/client", "reference/utilities/client",
"reference/warnings", "reference/warnings",

View File

@@ -281,15 +281,18 @@ html[data-theme="dark"] #carbonads .carbon-poweredby {
2. the "main" module would show up twice. 2. the "main" module would show up twice.
See sidebars.js See sidebars.js
*/ */
.reflection-category, .theme-doc-sidebar-item-link-level-2 [href="/reference/core/modules/main"] { .reflection-category,
.theme-doc-sidebar-item-link-level-2 [href="/reference/core/modules/main"],
.theme-doc-sidebar-item-link-level-2
[href="/reference/sveltekit/modules/main"] {
display: none; display: none;
} }
/* /*
HACK: to hide the "Classes" header and duplicate items together with the "typedoc-plugin-markdown" patch. HACK: to hide the "Classes" header and duplicate items together with the "typedoc-plugin-markdown" patch.
See: https://github.com/TypeStrong/typedoc/issues/2006 See: https://github.com/TypeStrong/typedoc/issues/2006
*/ */
#classes, h3.anchor + p:has(code, strong) { #classes,
h3.anchor + p:has(code, strong) {
display: none; display: none;
} }

View File

@@ -1,21 +1,21 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import * as React from 'react' import * as React from "react"
import Link from '@docusaurus/Link' import Link from "@docusaurus/Link"
import useBaseUrl from '@docusaurus/useBaseUrl' import useBaseUrl from "@docusaurus/useBaseUrl"
import useDocusaurusContext from '@docusaurus/useDocusaurusContext' import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
import CodeBlock from '@theme/CodeBlock' import CodeBlock from "@theme/CodeBlock"
import Layout from '@theme/Layout' import Layout from "@theme/Layout"
import classnames from 'classnames' import classnames from "classnames"
import { useEffect } from 'react' import { useEffect } from "react"
import ProviderMarquee from '../components/ProviderMarquee' import ProviderMarquee from "../components/ProviderMarquee"
import styles from './index.module.css' import styles from "./index.module.css"
import providers from '../../providers.json' import providers from "../../providers.json"
const providersCount = Object.keys(providers).length + 2 // email, credentials const providersCount = Object.keys(providers).length + 2 // email, credentials
const features = [ const features = [
{ {
title: 'Easy', title: "Easy",
imageUrl: 'img/undraw_social.svg', imageUrl: "img/undraw_social.svg",
description: ( description: (
<ul> <ul>
<li> <li>
@@ -31,11 +31,11 @@ const features = [
Use with <i>any</i> username / password store Use with <i>any</i> username / password store
</li> </li>
</ul> </ul>
) ),
}, },
{ {
title: 'Flexible', title: "Flexible",
imageUrl: 'img/undraw_authentication.svg', imageUrl: "img/undraw_authentication.svg",
description: ( description: (
<ul> <ul>
<li> <li>
@@ -55,11 +55,11 @@ const features = [
</li> </li>
<li>Choose database sessions or JWT</li> <li>Choose database sessions or JWT</li>
</ul> </ul>
) ),
}, },
{ {
title: 'Secure', title: "Secure",
imageUrl: 'img/undraw_secure.svg', imageUrl: "img/undraw_secure.svg",
description: ( description: (
<ul> <ul>
<li>Signed, prefixed, server-only cookies</li> <li>Signed, prefixed, server-only cookies</li>
@@ -68,18 +68,18 @@ const features = [
{/* <li>Tab syncing, auto-revalidation, keepalives</li> */} {/* <li>Tab syncing, auto-revalidation, keepalives</li> */}
<li>Doesn't rely on client side JavaScript</li> <li>Doesn't rely on client side JavaScript</li>
</ul> </ul>
) ),
} },
] ]
const kFormatter = (num) => { const kFormatter = (num) => {
return Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + 'k' return Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + "k"
} }
function Feature ({ imageUrl, title, description }) { function Feature({ imageUrl, title, description }) {
const imgUrl = useBaseUrl(imageUrl) const imgUrl = useBaseUrl(imageUrl)
return ( return (
<div className={classnames('col col--4', styles.feature)}> <div className={classnames("col col--4", styles.feature)}>
{imgUrl && ( {imgUrl && (
<div className="text--center"> <div className="text--center">
<div className="feature-image-wrapper"> <div className="feature-image-wrapper">
@@ -93,28 +93,28 @@ function Feature ({ imageUrl, title, description }) {
) )
} }
export default function Home () { export default function Home() {
const context = useDocusaurusContext() const context = useDocusaurusContext()
const { siteConfig = {} } = context const { siteConfig = {} } = context
useEffect(() => { useEffect(() => {
window window
.fetch('https://api.github.com/repos/nextauthjs/next-auth') .fetch("https://api.github.com/repos/nextauthjs/next-auth")
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
const navLinks = document.getElementsByClassName( const navLinks = document.getElementsByClassName(
'navbar__item navbar__link' "navbar__item navbar__link"
) )
const githubStat = document.createElement('span') const githubStat = document.createElement("span")
githubStat.innerHTML = kFormatter(data.stargazers_count) githubStat.innerHTML = kFormatter(data.stargazers_count)
githubStat.className = 'github-counter' githubStat.className = "github-counter"
navLinks[4].appendChild(githubStat) navLinks[4].appendChild(githubStat)
}) })
}, []) }, [])
return ( return (
<Layout description={siteConfig.tagline}> <Layout description={siteConfig.tagline}>
<div className="home-wrapper"> <div className="home-wrapper">
<header className={classnames('hero', styles.heroBanner)}> <header className={classnames("hero", styles.heroBanner)}>
<div className="container"> <div className="container">
<div className="hero-inner"> <div className="hero-inner">
<img <img
@@ -129,7 +129,7 @@ export default function Home () {
<div className={styles.buttons}> <div className={styles.buttons}>
<a <a
className={classnames( className={classnames(
'button button--outline button--secondary button--lg rounded-pill', "button button--outline button--secondary button--lg rounded-pill",
styles.button styles.button
)} )}
href="https://next-auth-example.vercel.app" href="https://next-auth-example.vercel.app"
@@ -138,7 +138,7 @@ export default function Home () {
</a> </a>
<a <a
className={classnames( className={classnames(
'button button--outline button--secondary button--lg rounded-pill', "button button--outline button--secondary button--lg rounded-pill",
styles.button styles.button
)} )}
href="https://sveltekit-auth-example.vercel.app" href="https://sveltekit-auth-example.vercel.app"
@@ -147,10 +147,10 @@ export default function Home () {
</a> </a>
<Link <Link
className={classnames( className={classnames(
'button button--primary button--lg rounded-pill', "button button--primary button--lg rounded-pill",
styles.button styles.button
)} )}
to={useBaseUrl('/getting-started/introduction')} to={useBaseUrl("/getting-started/introduction")}
> >
Get Started Get Started
</Link> </Link>
@@ -170,7 +170,7 @@ export default function Home () {
<div className="row"> <div className="row">
<div className="col"> <div className="col">
<h2 className={styles.featuresTitle}> <h2 className={styles.featuresTitle}>
<span>Open Source.</span> <span>Full Stack.</span>{' '} <span>Open Source.</span> <span>Full Stack.</span>{" "}
<span>Own Your Data.</span> <span>Own Your Data.</span>
</h2> </h2>
</div> </div>
@@ -198,7 +198,7 @@ export default function Home () {
</div> </div>
<div className="row"> <div className="row">
<div className="col"> <div className="col">
<h2 className="text--center" style={{ fontSize: '2.5rem' }}> <h2 className="text--center" style={{ fontSize: "2.5rem" }}>
Add authentication in minutes! Add authentication in minutes!
</h2> </h2>
</div> </div>
@@ -227,7 +227,7 @@ export default function Home () {
</div> </div>
<div className="row"> <div className="row">
<div className="col"> <div className="col">
<p className="text--center" style={{ marginTop: '2rem' }}> <p className="text--center" style={{ marginTop: "2rem" }}>
<Link <Link
to="/getting-started/introduction" to="/getting-started/introduction"
className="button button--primary button--lg rounded-pill" className="button button--primary button--lg rounded-pill"

View File

@@ -70,7 +70,7 @@
"clean": "rm -rf *.js *.d.ts lib providers", "clean": "rm -rf *.js *.d.ts lib providers",
"css": "node ./scripts/generate-css.js", "css": "node ./scripts/generate-css.js",
"lint": "pnpm prettier --check src && eslint src", "lint": "pnpm prettier --check src && eslint src",
"format": "pnpm lint --fix", "format": "pnpm prettier --write . && eslint src --fix",
"dev": "pnpm css && tsc -w" "dev": "pnpm css && tsc -w"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -210,6 +210,7 @@ export interface AuthConfig {
* Pages specified will override the corresponding built-in page. * Pages specified will override the corresponding built-in page.
* * **Default value**: `{}` * * **Default value**: `{}`
* * **Required**: *No* * * **Required**: *No*
*
* @example * @example
* *
* ```ts * ```ts
@@ -349,6 +350,7 @@ export interface AuthConfig {
* - ⚠ **This is an advanced option.** Advanced options are passed the same way as basic options, * - ⚠ **This is an advanced option.** Advanced options are passed the same way as basic options,
* but **may have complex implications** or side effects. * but **may have complex implications** or side effects.
* You should **try to avoid using advanced options** unless you are very comfortable using them. * You should **try to avoid using advanced options** unless you are very comfortable using them.
*
* @default Boolean(process.env.NEXTAUTH_URL ?? process.env.AUTH_TRUST_HOST ?? process.env.VERCEL) * @default Boolean(process.env.NEXTAUTH_URL ?? process.env.AUTH_TRUST_HOST ?? process.env.VERCEL)
*/ */
trustHost?: boolean trustHost?: boolean

View File

@@ -1,29 +1,29 @@
import type { import type {
InternalProvider, InternalProvider,
SignInPageErrorParam, SignInPageErrorParam,
Theme Theme,
} from '../../types.js' } from "../../types.js"
const signinErrors: Record< const signinErrors: Record<
Lowercase<SignInPageErrorParam | 'default'>, Lowercase<SignInPageErrorParam | "default">,
string string
> = { > = {
default: 'Unable to sign in.', default: "Unable to sign in.",
signin: 'Try signing in with a different account.', signin: "Try signing in with a different account.",
oauthsignin: 'Try signing in with a different account.', oauthsignin: "Try signing in with a different account.",
oauthcallback: 'Try signing in with a different account.', oauthcallback: "Try signing in with a different account.",
oauthcreateaccount: 'Try signing in with a different account.', oauthcreateaccount: "Try signing in with a different account.",
emailcreateaccount: 'Try signing in with a different account.', emailcreateaccount: "Try signing in with a different account.",
callback: 'Try signing in with a different account.', callback: "Try signing in with a different account.",
oauthaccountnotlinked: oauthaccountnotlinked:
'To confirm your identity, sign in with the same account you used originally.', "To confirm your identity, sign in with the same account you used originally.",
emailsignin: 'The e-mail could not be sent.', emailsignin: "The e-mail could not be sent.",
credentialssignin: credentialssignin:
'Sign in failed. Check the details you provided are correct.', "Sign in failed. Check the details you provided are correct.",
sessionrequired: 'Please sign in to access this page.' sessionrequired: "Please sign in to access this page.",
} }
export default function SigninPage (props: { export default function SigninPage(props: {
csrfToken: string csrfToken: string
providers: InternalProvider[] providers: InternalProvider[]
callbackUrl: string callbackUrl: string
@@ -37,12 +37,12 @@ export default function SigninPage (props: {
callbackUrl, callbackUrl,
theme, theme,
email, email,
error: errorType error: errorType,
} = props } = props
if (typeof document !== 'undefined' && theme.brandColor) { if (typeof document !== "undefined" && theme.brandColor) {
document.documentElement.style.setProperty( document.documentElement.style.setProperty(
'--brand-color', "--brand-color",
theme.brandColor theme.brandColor
) )
} }
@@ -52,13 +52,13 @@ export default function SigninPage (props: {
// TODO: move logos // TODO: move logos
const logos = const logos =
'https://raw.githubusercontent.com/nextauthjs/next-auth/main/packages/next-auth/provider-logos' "https://raw.githubusercontent.com/nextauthjs/next-auth/main/packages/next-auth/provider-logos"
return ( return (
<div className="signin"> <div className="signin">
{theme.brandColor && ( {theme.brandColor && (
<style <style
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: `:root {--brand-color: ${theme.brandColor}}` __html: `:root {--brand-color: ${theme.brandColor}}`,
}} }}
/> />
)} )}
@@ -71,8 +71,7 @@ export default function SigninPage (props: {
)} )}
{providers.map((provider, i) => ( {providers.map((provider, i) => (
<div key={provider.id} className="provider"> <div key={provider.id} className="provider">
{provider.type === 'oauth' || provider.type === 'oidc' {provider.type === "oauth" || provider.type === "oidc" ? (
? (
<form action={provider.signinUrl} method="POST"> <form action={provider.signinUrl} method="POST">
<input type="hidden" name="csrfToken" value={csrfToken} /> <input type="hidden" name="csrfToken" value={csrfToken} />
{callbackUrl && ( {callbackUrl && (
@@ -82,17 +81,17 @@ export default function SigninPage (props: {
type="submit" type="submit"
className="button" className="button"
style={{ style={{
'--provider-bg': provider.style?.bg ?? '', "--provider-bg": provider.style?.bg ?? "",
'--provider-dark-bg': provider.style?.bgDark ?? '', "--provider-dark-bg": provider.style?.bgDark ?? "",
'--provider-color': provider.style?.text ?? '', "--provider-color": provider.style?.text ?? "",
'--provider-dark-color': provider.style?.textDark ?? '' "--provider-dark-color": provider.style?.textDark ?? "",
}} }}
> >
{provider.style?.logo && ( {provider.style?.logo && (
<img <img
id="provider-logo" id="provider-logo"
src={`${ src={`${
provider.style.logo.startsWith('/') ? logos : '' provider.style.logo.startsWith("/") ? logos : ""
}${provider.style.logo}`} }${provider.style.logo}`}
/> />
)} )}
@@ -100,20 +99,19 @@ export default function SigninPage (props: {
<img <img
id="provider-logo-dark" id="provider-logo-dark"
src={`${ src={`${
provider.style.logo.startsWith('/') ? logos : '' provider.style.logo.startsWith("/") ? logos : ""
}${provider.style.logoDark}`} }${provider.style.logoDark}`}
/> />
)} )}
<span>Sign in with {provider.name}</span> <span>Sign in with {provider.name}</span>
</button> </button>
</form> </form>
) ) : null}
: null} {(provider.type === "email" || provider.type === "credentials") &&
{(provider.type === 'email' || provider.type === 'credentials') &&
i > 0 && i > 0 &&
providers[i - 1].type !== 'email' && providers[i - 1].type !== "email" &&
providers[i - 1].type !== 'credentials' && <hr />} providers[i - 1].type !== "credentials" && <hr />}
{provider.type === 'email' && ( {provider.type === "email" && (
<form action={provider.signinUrl} method="POST"> <form action={provider.signinUrl} method="POST">
<input type="hidden" name="csrfToken" value={csrfToken} /> <input type="hidden" name="csrfToken" value={csrfToken} />
<label <label
@@ -134,7 +132,7 @@ export default function SigninPage (props: {
<button type="submit">Sign in with {provider.name}</button> <button type="submit">Sign in with {provider.name}</button>
</form> </form>
)} )}
{provider.type === 'credentials' && ( {provider.type === "credentials" && (
<form action={provider.callbackUrl} method="POST"> <form action={provider.callbackUrl} method="POST">
<input type="hidden" name="csrfToken" value={csrfToken} /> <input type="hidden" name="csrfToken" value={csrfToken} />
{Object.keys(provider.credentials).map((credential) => { {Object.keys(provider.credentials).map((credential) => {
@@ -149,9 +147,9 @@ export default function SigninPage (props: {
<input <input
name={credential} name={credential}
id={`input-${credential}-for-${provider.id}-provider`} id={`input-${credential}-for-${provider.id}-provider`}
type={provider.credentials[credential].type ?? 'text'} type={provider.credentials[credential].type ?? "text"}
placeholder={ placeholder={
provider.credentials[credential].placeholder ?? '' provider.credentials[credential].placeholder ?? ""
} }
{...provider.credentials[credential]} {...provider.credentials[credential]}
/> />
@@ -161,7 +159,7 @@ export default function SigninPage (props: {
<button type="submit">Sign in with {provider.name}</button> <button type="submit">Sign in with {provider.name}</button>
</form> </form>
)} )}
{(provider.type === 'email' || provider.type === 'credentials') && {(provider.type === "email" || provider.type === "credentials") &&
i + 1 < providers.length && <hr />} i + 1 < providers.length && <hr />}
</div> </div>
))} ))}

View File

@@ -5,9 +5,13 @@ import { createHash } from "../web.js"
import { handleAuthorized } from "./shared.js" import { handleAuthorized } from "./shared.js"
import type { AdapterSession } from "../../adapters.js" import type { AdapterSession } from "../../adapters.js"
import type { RequestInternal, ResponseInternal, User } from "../../types.js" import type {
RequestInternal,
ResponseInternal,
User,
InternalOptions,
} from "../../types.js"
import type { Cookie, SessionStore } from "../cookie.js" import type { Cookie, SessionStore } from "../cookie.js"
import type { InternalOptions } from "../../types.js"
/** Handle callbacks from login services */ /** Handle callbacks from login services */
export async function callback(params: { export async function callback(params: {

View File

@@ -1,6 +1,6 @@
import { AuthError } from '../../errors.js' import { AuthError } from "../../errors.js"
export type WarningCode = 'debug_enabled' export type WarningCode = "debug_enabled"
/** /**
* Override any of the methods, and the rest will use the default logger. * Override any of the methods, and the rest will use the default logger.
@@ -13,13 +13,13 @@ export interface LoggerInstance extends Record<string, Function> {
debug: (message: string, metadata?: unknown) => void debug: (message: string, metadata?: unknown) => void
} }
const red = '\x1b[31m' const red = "\x1b[31m"
const yellow = '\x1b[33m' const yellow = "\x1b[33m"
const grey = '\x1b[90m' const grey = "\x1b[90m"
const reset = '\x1b[0m' const reset = "\x1b[0m"
export const logger: LoggerInstance = { export const logger: LoggerInstance = {
error (error: AuthError) { error(error: AuthError) {
const url = `https://errors.authjs.dev#${error.name.toLowerCase()}` const url = `https://errors.authjs.dev#${error.name.toLowerCase()}`
console.error(error.stack) console.error(error.stack)
console.error( console.error(
@@ -27,23 +27,23 @@ export const logger: LoggerInstance = {
) )
error.metadata && console.error(JSON.stringify(error.metadata, null, 2)) error.metadata && console.error(JSON.stringify(error.metadata, null, 2))
}, },
warn (code) { warn(code) {
const url = `https://errors.authjs.dev#${code}` const url = `https://errors.authjs.dev#${code}`
console.warn(`${yellow}[auth][warn][${code}]${reset}`, `Read more: ${url}`) console.warn(`${yellow}[auth][warn][${code}]${reset}`, `Read more: ${url}`)
}, },
debug (message, metadata) { debug(message, metadata) {
console.log( console.log(
`${grey}[auth][debug]:${reset} ${message}`, `${grey}[auth][debug]:${reset} ${message}`,
JSON.stringify(metadata, null, 2) JSON.stringify(metadata, null, 2)
) )
} },
} }
/** /**
* Override the built-in logger with user's implementation. * Override the built-in logger with user's implementation.
* Any `undefined` level will use the default logger. * Any `undefined` level will use the default logger.
*/ */
export function setLogger ( export function setLogger(
newLogger: Partial<LoggerInstance> = {}, newLogger: Partial<LoggerInstance> = {},
debug?: boolean debug?: boolean
) { ) {

View File

@@ -1,5 +1,5 @@
import type { CommonProviderOptions } from "./index.js" import type { CommonProviderOptions } from "./index.js"
import type { Awaitable, RequestInternal, User } from "../types.js" import type { Awaitable, User } from "../types.js"
import type { JSXInternal } from "preact/src/jsx.js" import type { JSXInternal } from "preact/src/jsx.js"
/** /**

View File

@@ -1,6 +1,6 @@
import { Profile } from "../types.js" import { Profile } from "../types.js"
import CredentialsProvider from "./credentials.js"
import type { import type {
default as CredentialsProvider,
CredentialsConfig, CredentialsConfig,
CredentialsProviderType, CredentialsProviderType,
} from "./credentials.js" } from "./credentials.js"

View File

@@ -55,24 +55,24 @@
* @module types * @module types
*/ */
import type { CookieSerializeOptions } from 'cookie' import type { CookieSerializeOptions } from "cookie"
import type { import type {
OAuth2TokenEndpointResponse, OAuth2TokenEndpointResponse,
OpenIDTokenEndpointResponse OpenIDTokenEndpointResponse,
} from 'oauth4webapi' } from "oauth4webapi"
import type { Adapter, AdapterUser } from './adapters.js' import type { Adapter, AdapterUser } from "./adapters.js"
import type { import type {
CredentialInput, CredentialInput,
CredentialsConfig, CredentialsConfig,
EmailConfig, EmailConfig,
OAuthConfigInternal, OAuthConfigInternal,
ProviderType ProviderType,
} from './providers/index.js' } from "./providers/index.js"
import type { JWT, JWTOptions } from './jwt.js' import type { JWT, JWTOptions } from "./jwt.js"
import type { Cookie } from './lib/cookie.js' import type { Cookie } from "./lib/cookie.js"
import type { LoggerInstance } from './lib/utils/logger.js' import type { LoggerInstance } from "./lib/utils/logger.js"
export type { AuthConfig } from './index.js' export type { AuthConfig } from "./index.js"
export type Awaitable<T> = T | PromiseLike<T> export type Awaitable<T> = T | PromiseLike<T>
export type { LoggerInstance } export type { LoggerInstance }
@@ -83,7 +83,7 @@ export type { LoggerInstance }
* [Pages](https://authjs.dev/guides/basics/pages) * [Pages](https://authjs.dev/guides/basics/pages)
*/ */
export interface Theme { export interface Theme {
colorScheme?: 'auto' | 'dark' | 'light' colorScheme?: "auto" | "dark" | "light"
logo?: string logo?: string
brandColor?: string brandColor?: string
buttonText?: string buttonText?: string
@@ -95,7 +95,7 @@ export interface Theme {
* but they refer to the same value. * but they refer to the same value.
*/ */
export type TokenSet = Partial< export type TokenSet = Partial<
OAuth2TokenEndpointResponse | OpenIDTokenEndpointResponse OAuth2TokenEndpointResponse | OpenIDTokenEndpointResponse
> >
/** /**
@@ -260,8 +260,8 @@ export interface EventCallbacks {
*/ */
signOut: ( signOut: (
message: message:
| { session: Awaited<ReturnType<Adapter['deleteSession']>> } | { session: Awaited<ReturnType<Adapter["deleteSession"]>> }
| { token: Awaited<ReturnType<JWTOptions['decode']>> } | { token: Awaited<ReturnType<JWTOptions["decode"]>> }
) => Awaitable<void> ) => Awaitable<void>
createUser: (message: { user: User }) => Awaitable<void> createUser: (message: { user: User }) => Awaitable<void>
updateUser: (message: { user: User }) => Awaitable<void> updateUser: (message: { user: User }) => Awaitable<void>
@@ -276,26 +276,26 @@ export interface EventCallbacks {
* - `token`: The JWT token for this session. * - `token`: The JWT token for this session.
* - `session`: The session object from your adapter. * - `session`: The session object from your adapter.
*/ */
session: (message: { session: Session, token: JWT }) => Awaitable<void> session: (message: { session: Session; token: JWT }) => Awaitable<void>
} }
export type EventType = keyof EventCallbacks export type EventType = keyof EventCallbacks
/** TODO: Check if all these are used/correct */ /** TODO: Check if all these are used/correct */
export type ErrorPageParam = 'Configuration' | 'AccessDenied' | 'Verification' export type ErrorPageParam = "Configuration" | "AccessDenied" | "Verification"
/** TODO: Check if all these are used/correct */ /** TODO: Check if all these are used/correct */
export type SignInPageErrorParam = export type SignInPageErrorParam =
| 'Signin' | "Signin"
| 'OAuthSignin' | "OAuthSignin"
| 'OAuthCallback' | "OAuthCallback"
| 'OAuthCreateAccount' | "OAuthCreateAccount"
| 'EmailCreateAccount' | "EmailCreateAccount"
| 'Callback' | "Callback"
| 'OAuthAccountNotLinked' | "OAuthAccountNotLinked"
| 'EmailSignin' | "EmailSignin"
| 'CredentialsSignin' | "CredentialsSignin"
| 'SessionRequired' | "SessionRequired"
export interface PagesOptions { export interface PagesOptions {
/** /**
@@ -344,7 +344,7 @@ export interface DefaultSession {
*/ */
export interface Session extends DefaultSession {} export interface Session extends DefaultSession {}
export type SessionStrategy = 'jwt' | 'database' export type SessionStrategy = "jwt" | "database"
/** [Documentation](https://authjs.dev/reference/configuration/auth-config#session) */ /** [Documentation](https://authjs.dev/reference/configuration/auth-config#session) */
export interface SessionOptions { export interface SessionOptions {
@@ -406,31 +406,31 @@ export interface User extends DefaultUser {}
// Below are types that are only supposed be used by next-auth internally // Below are types that are only supposed be used by next-auth internally
/** @internal */ /** @internal */
export type InternalProvider<T = ProviderType> = (T extends 'oauth' export type InternalProvider<T = ProviderType> = (T extends "oauth"
? OAuthConfigInternal<any> ? OAuthConfigInternal<any>
: T extends 'email' : T extends "email"
? EmailConfig ? EmailConfig
: T extends 'credentials' : T extends "credentials"
? CredentialsConfig ? CredentialsConfig
: never) & { : never) & {
signinUrl: string signinUrl: string
callbackUrl: string callbackUrl: string
} }
export type AuthAction = export type AuthAction =
| 'providers' | "providers"
| 'session' | "session"
| 'csrf' | "csrf"
| 'signin' | "signin"
| 'signout' | "signout"
| 'callback' | "callback"
| 'verify-request' | "verify-request"
| 'error' | "error"
/** @internal */ /** @internal */
export interface RequestInternal { export interface RequestInternal {
url: URL url: URL
method: 'GET' | 'POST' method: "GET" | "POST"
cookies?: Partial<Record<string, string>> cookies?: Partial<Record<string, string>>
headers?: Record<string, any> headers?: Record<string, any>
query?: Record<string, any> query?: Record<string, any>

View File

@@ -5,14 +5,7 @@
"emitDeclarationOnly": false "emitDeclarationOnly": false
}, },
"watchOptions": { "watchOptions": {
"excludeDirectories": [ "excludeDirectories": ["jwt", "lib", "providers"],
"jwt", "excludeFiles": ["./*.d.ts", "./*.js"]
"lib",
"providers",
],
"excludeFiles": [
"./*.d.ts",
"./*.js"
]
} }
} }

View File

@@ -1,7 +1,4 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"exclude": [ "exclude": ["./*.js", "./*.d.ts"]
"./*.js",
"./*.d.ts"
]
} }

View File

@@ -6,11 +6,7 @@
"isolatedModules": true, "isolatedModules": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "preact", "jsxImportSource": "preact",
"lib": [ "lib": ["dom", "dom.iterable", "esnext"],
"dom",
"dom.iterable",
"esnext"
],
"target": "ES2020", "target": "ES2020",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
@@ -21,16 +17,8 @@
"strictNullChecks": true, "strictNullChecks": true,
"stripInternal": true, "stripInternal": true,
"declarationMap": true, "declarationMap": true,
"declaration": true, "declaration": true
}, },
"include": [ "include": ["src/**/*"],
"src/**/*", "exclude": ["adapters.*", "index.*", "jwt", "lib", "providers"]
],
"exclude": [
"adapters.*",
"index.*",
"jwt",
"lib",
"providers",
],
} }

View File

@@ -1,32 +1,105 @@
/**
*
*
* :::warning
* `@auth/sveltekit` is currently experimental. The API _will_ change in the future.
* :::
*
* SvelteKit Auth is the official SvelteKit integration for Auth.js.
* It provides a simple way to add authentication to your SvelteKit app in a few lines of code.
*
*
* ## Installation
*
* ```bash npm2yarn2pnpm
* npm install @auth/core @auth/sveltekit
* ```
*
* ## Usage
*
* ```ts title="src/hooks.server.ts"
* import SvelteKitAuth from "@auth/sveltekit"
* import GitHub from "@auth/core/providers/github"
* import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
*
* export const handle = SvelteKitAuth({
* providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
* })
* ```
*
* Don't forget to set the `AUTH_SECRET` [environment variable](https://kit.svelte.dev/docs/modules#$env-static-private). This should be a random 32 character string. On unix systems you can use `openssl rand -hex 32` or check out `https://generate-secret.vercel.app/32`.
*
* When deploying your app outside Vercel, set the `AUTH_TRUST_HOST` variable to `true` for other hosting providers like Cloudflare Pages or Netlify.
*
* The callback URL used by the [providers](https://authjs.dev/reference/core/modules/providers) must be set to the following, unless you override {@link SvelteKitAuthConfig.prefix}:
* ```
* [origin]/auth/callback/[provider]
* ```
*
* ## Signing in and signing out
*
* ```ts
* <script>
* import { signIn, signOut } from "@auth/sveltekit/client"
* import { page } from "$app/stores"
* </script>
*
* <h1>SvelteKit Auth Example</h1>
* <p>
* {#if $page.data.session}
* {#if $page.data.session.user?.image}
* <span
* style="background-image: url('{$page.data.session.user.image}')"
* class="avatar"
* />
* {/if}
* <span class="signedInText">
* <small>Signed in as</small><br />
* <strong>{$page.data.session.user?.name ?? "User"}</strong>
* </span>
* <button on:click={() => signOut()} class="button">Sign out</button>
* {:else}
* <span class="notSignedInText">You are not signed in</span>
* <button on:click={() => signIn("github")}>Sign In with GitHub</button>
* {/if}
* </p>
* ```
*
* ## Notes
*
* :::info
* Learn more about `@auth/sveltekit` [here](https://vercel.com/blog/announcing-sveltekit-auth).
* :::
*
* :::info
* PRs to improve this documentation are welcome! See [this file](https://github.com/nextauthjs/next-auth/blob/main/packages/frameworks-sveltekit/src/lib/index.ts).
* :::
*
* @module main
*/
/// <reference types="@sveltejs/kit" /> /// <reference types="@sveltejs/kit" />
import type { Handle } from "@sveltejs/kit"
import { dev } from "$app/environment" import { dev } from "$app/environment"
import { env } from "$env/dynamic/private" import { env } from "$env/dynamic/private"
import { AUTH_SECRET } from "$env/static/private" import { AUTH_SECRET } from "$env/static/private"
import {
AuthHandler,
type AuthAction,
type AuthOptions,
type Session,
} from "@auth/core"
import type { Handle } from "@sveltejs/kit"
export type GetSessionResult = Promise<Session | null> import { Auth } from "@auth/core"
import type { AuthAction, AuthConfig, Session } from "@auth/core/types"
export async function getSession( export async function getSession(
req: Request, req: Request,
options: AuthOptions config: AuthConfig
): GetSessionResult { ): ReturnType<App.Locals["getSession"]> {
options.secret ??= AUTH_SECRET config.secret ??= AUTH_SECRET
options.trustHost ??= true config.trustHost ??= true
const url = new URL("/api/auth/session", req.url) const url = new URL("/api/auth/session", req.url)
const response = await AuthHandler( const request = new Request(url, { headers: req.headers })
new Request(url, { headers: req.headers }), const response = await Auth(request, config)
options
)
const { status = 200 } = response const { status = 200 } = response
const data = await response.json() const data = await response.json()
if (!data || !Object.keys(data).length) return null if (!data || !Object.keys(data).length) return null
@@ -34,10 +107,14 @@ export async function getSession(
throw new Error(data.message) throw new Error(data.message)
} }
export interface SvelteKitAuthOptions extends AuthOptions { /** Configure the {@link SvelteKitAuth} method. */
export interface SvelteKitAuthConfig extends AuthConfig {
/** /**
* Defines the base path for the auth routes. * Defines the base path for the auth routes.
* @default '/auth' * If you change the default value,
* you must also update the callback URL used by the [providers](https://authjs.dev/reference/core/modules/providers).
*
* @default "/auth"
*/ */
prefix?: string prefix?: string
} }
@@ -51,27 +128,23 @@ const actions: AuthAction[] = [
"callback", "callback",
"verify-request", "verify-request",
"error", "error",
"_log",
] ]
function SvelteKitAuthHandler( function AuthHandle(prefix: string, authOptions: AuthConfig): Handle {
prefix: string, return function ({ event, resolve }) {
authOptions: AuthOptions
): Handle {
return ({ event, resolve }) => {
const { url, request } = event const { url, request } = event
event.locals.getSession ??= () => getSession(request, authOptions) event.locals.getSession ??= () => getSession(request, authOptions)
const [action] = url.pathname.slice(prefix.length + 1).split("/") const action = url.pathname
if ( .slice(prefix.length + 1)
actions.includes(action as AuthAction) && .split("/")[0] as AuthAction
url.pathname.startsWith(prefix + "/")
) { if (!actions.includes(action) || !url.pathname.startsWith(prefix + "/")) {
return AuthHandler(request, authOptions) return resolve(event)
} }
return resolve(event) return Auth(request, authOptions)
} }
} }
@@ -79,19 +152,18 @@ function SvelteKitAuthHandler(
* The main entry point to `@auth/sveltekit` * The main entry point to `@auth/sveltekit`
* @see https://sveltekit.authjs.dev * @see https://sveltekit.authjs.dev
*/ */
export default function SvelteKitAuth(options: SvelteKitAuthOptions): Handle { export function SvelteKitAuth(options: SvelteKitAuthConfig): Handle {
const { prefix = "/auth", ...authOptions } = options const { prefix = "/auth", ...authOptions } = options
authOptions.secret ??= AUTH_SECRET authOptions.secret ??= AUTH_SECRET
authOptions.trustHost ??= !!(env.AUTH_TRUST_HOST ?? env.VERCEL ?? dev) authOptions.trustHost ??= !!(env.AUTH_TRUST_HOST ?? env.VERCEL ?? dev)
return AuthHandle(prefix, authOptions)
return SvelteKitAuthHandler(prefix, authOptions)
} }
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace // eslint-disable-next-line @typescript-eslint/no-namespace
namespace App { namespace App {
interface Locals { interface Locals {
getSession: () => GetSessionResult getSession(): Promise<Session | null>
} }
interface PageData { interface PageData {
session: Session | null session: Session | null

22
pnpm-lock.yaml generated
View File

@@ -130,6 +130,8 @@ importers:
docs: docs:
specifiers: specifiers:
'@auth/core': workspace:*
'@auth/sveltekit': workspace:*
'@docusaurus/core': 2.2.0 '@docusaurus/core': 2.2.0
'@docusaurus/eslint-plugin': 2.2.0 '@docusaurus/eslint-plugin': 2.2.0
'@docusaurus/module-type-aliases': 2.2.0 '@docusaurus/module-type-aliases': 2.2.0
@@ -149,6 +151,8 @@ importers:
remark-github: 10.1.0 remark-github: 10.1.0
styled-components: 5.3.6 styled-components: 5.3.6
dependencies: dependencies:
'@auth/core': link:../packages/core
'@auth/sveltekit': link:../packages/frameworks-sveltekit
'@mdx-js/react': 1.6.22_react@18.2.0 '@mdx-js/react': 1.6.22_react@18.2.0
'@sapphire/docusaurus-plugin-npm2yarn2pnpm': 1.1.4 '@sapphire/docusaurus-plugin-npm2yarn2pnpm': 1.1.4
classnames: 2.3.2 classnames: 2.3.2
@@ -11085,8 +11089,10 @@ packages:
indent-string: 4.0.0 indent-string: 4.0.0
dev: true dev: true
/ajv-formats/2.1.1: /ajv-formats/2.1.1_ajv@8.11.0:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
ajv: ^8.0.0
peerDependenciesMeta: peerDependenciesMeta:
ajv: ajv:
optional: true optional: true
@@ -12942,8 +12948,8 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
dependencies: dependencies:
is-text-path: 1.0.1
JSONStream: 1.3.5 JSONStream: 1.3.5
is-text-path: 1.0.1
lodash: 4.17.21 lodash: 4.17.21
meow: 8.1.2 meow: 8.1.2
split2: 3.2.2 split2: 3.2.2
@@ -15801,7 +15807,7 @@ packages:
dependencies: dependencies:
'@apidevtools/json-schema-ref-parser': 9.0.9 '@apidevtools/json-schema-ref-parser': 9.0.9
ajv: 8.11.0 ajv: 8.11.0
ajv-formats: 2.1.1 ajv-formats: 2.1.1_ajv@8.11.0
body-parser: 1.20.0 body-parser: 1.20.0
content-type: 1.0.4 content-type: 1.0.4
deep-freeze: 0.0.1 deep-freeze: 0.0.1
@@ -24661,6 +24667,12 @@ packages:
/react-dev-utils/12.0.1_webpack@5.73.0: /react-dev-utils/12.0.1_webpack@5.73.0:
resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==}
engines: {node: '>=14'} engines: {node: '>=14'}
peerDependencies:
typescript: '>=2.7'
webpack: '>=4'
peerDependenciesMeta:
typescript:
optional: true
dependencies: dependencies:
'@babel/code-frame': 7.18.6 '@babel/code-frame': 7.18.6
address: 1.2.0 address: 1.2.0
@@ -24690,9 +24702,7 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- eslint - eslint
- supports-color - supports-color
- typescript
- vue-template-compiler - vue-template-compiler
- webpack
dev: true dev: true
/react-dom/18.2.0_react@18.2.0: /react-dom/18.2.0_react@18.2.0:
@@ -25535,7 +25545,7 @@ packages:
dependencies: dependencies:
'@types/json-schema': 7.0.11 '@types/json-schema': 7.0.11
ajv: 8.11.0 ajv: 8.11.0
ajv-formats: 2.1.1 ajv-formats: 2.1.1_ajv@8.11.0
ajv-keywords: 5.1.0_ajv@8.11.0 ajv-keywords: 5.1.0_ajv@8.11.0
dev: true dev: true