Add eslint configs, fix lint errors
This commit is contained in:
parent
631f98aaaf
commit
19c5725847
45 changed files with 388 additions and 164 deletions
|
@ -1,3 +1,11 @@
|
|||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"root": true,
|
||||
"ignorePatterns": ["node_modules/", "__tests__/"]
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ import config from "@lib/config"
|
|||
import Auth from "../components"
|
||||
|
||||
function isGithubEnabled() {
|
||||
return config.github_client_id.length && config.github_client_secret.length ? true : false
|
||||
return config.github_client_id.length && config.github_client_secret.length
|
||||
? true
|
||||
: false
|
||||
}
|
||||
|
||||
export default function SignInPage() {
|
||||
|
|
|
@ -7,10 +7,18 @@ const getPasscode = async () => {
|
|||
}
|
||||
|
||||
function isGithubEnabled() {
|
||||
return config.github_client_id.length && config.github_client_secret.length ? true : false
|
||||
return config.github_client_id.length && config.github_client_secret.length
|
||||
? true
|
||||
: false
|
||||
}
|
||||
|
||||
export default async function SignUpPage() {
|
||||
const requiresPasscode = await getPasscode()
|
||||
return <Auth page="signup" requiresServerPassword={requiresPasscode} isGithubEnabled={isGithubEnabled()} />
|
||||
return (
|
||||
<Auth
|
||||
page="signup"
|
||||
requiresServerPassword={requiresPasscode}
|
||||
isGithubEnabled={isGithubEnabled()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
import { Popover } from "@components/popover"
|
||||
import { codeFileExtensions } from "@lib/constants"
|
||||
import clsx from "clsx"
|
||||
import type { File, PostWithFiles } from "lib/server/prisma"
|
||||
import type { PostWithFiles } from "lib/server/prisma"
|
||||
import styles from "./dropdown.module.css"
|
||||
import buttonStyles from "@components/button/button.module.css"
|
||||
import { ChevronDown, Code, File as FileIcon } from "react-feather"
|
||||
import { Spinner } from "@components/spinner"
|
||||
import Link from "next/link"
|
||||
|
||||
type Item = File & {
|
||||
icon: JSX.Element
|
||||
}
|
||||
|
||||
const FileDropdown = ({
|
||||
files,
|
||||
loading
|
||||
|
@ -23,9 +19,7 @@ const FileDropdown = ({
|
|||
return (
|
||||
<Popover>
|
||||
<Popover.Trigger className={buttonStyles.button}>
|
||||
<div
|
||||
style={{ minWidth: 125 }}
|
||||
>
|
||||
<div style={{ minWidth: 125 }}>
|
||||
<Spinner />
|
||||
</div>
|
||||
</Popover.Trigger>
|
||||
|
|
|
@ -37,7 +37,7 @@ const MarkdownPreview = ({
|
|||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body,
|
||||
body
|
||||
})
|
||||
|
||||
if (resp.ok) {
|
||||
|
|
|
@ -55,6 +55,7 @@ const Post = ({
|
|||
title: doc.title,
|
||||
content: doc.content,
|
||||
id: doc.id
|
||||
// eslint-disable-next-line no-mixed-spaces-and-tabs
|
||||
}))
|
||||
: [emptyDoc]
|
||||
|
||||
|
@ -300,7 +301,7 @@ const Post = ({
|
|||
placeholderText="Won't expire"
|
||||
selected={expiresAt}
|
||||
showTimeInput={true}
|
||||
// @ts-ignore
|
||||
// @ts-expect-error fix time input type
|
||||
customTimeInput={<CustomTimeInput />}
|
||||
timeInputLabel="Time:"
|
||||
dateFormat="MM/dd/yyyy h:mm aa"
|
||||
|
|
|
@ -31,7 +31,7 @@ const NewFromExisting = async ({
|
|||
select: {
|
||||
title: true,
|
||||
content: true,
|
||||
id: true,
|
||||
id: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import { getCurrentUser } from "@lib/server/session"
|
||||
import { redirect } from "next/navigation"
|
||||
|
||||
export default function NewLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ const New = () => <NewPost />
|
|||
|
||||
export default New
|
||||
|
||||
export const dynamic = 'force-static'
|
||||
export const dynamic = "force-static"
|
||||
|
|
|
@ -26,9 +26,11 @@ export const PostTitle = ({
|
|||
}: TitleProps) => {
|
||||
return (
|
||||
<span className={styles.title}>
|
||||
<h1 style={{
|
||||
<h1
|
||||
style={{
|
||||
fontSize: "1.175rem"
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{title}{" "}
|
||||
<span style={{ color: "var(--gray)" }}>
|
||||
by{" "}
|
||||
|
|
|
@ -77,11 +77,13 @@ const PostFiles = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<main style={{
|
||||
<main
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "var(--gap-double)"
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{post.files?.map(({ id, content, title, html }) => (
|
||||
<DocumentComponent
|
||||
skeleton={false}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
"use client"
|
||||
|
||||
import { memo, useEffect } from "react"
|
||||
import styles from "./document.module.css"
|
||||
import Skeleton from "@components/skeleton"
|
||||
import Link from "next/link"
|
||||
|
||||
import Tooltip from "@components/tooltip"
|
||||
import Button from "@components/button"
|
||||
import ButtonGroup from "@components/button-group"
|
||||
import Skeleton from "@components/skeleton"
|
||||
import Tooltip from "@components/tooltip"
|
||||
import DocumentTabs from "app/(posts)/components/tabs"
|
||||
import Link from "next/link"
|
||||
import { memo } from "react"
|
||||
import { Download, ExternalLink } from "react-feather"
|
||||
import styles from "./document.module.css"
|
||||
|
||||
type SharedProps = {
|
||||
title?: string
|
||||
|
@ -22,9 +21,11 @@ type SharedProps = {
|
|||
type Props = (
|
||||
| {
|
||||
skeleton?: true
|
||||
// eslint-disable-next-line no-mixed-spaces-and-tabs
|
||||
}
|
||||
| {
|
||||
skeleton?: false
|
||||
// eslint-disable-next-line no-mixed-spaces-and-tabs
|
||||
}
|
||||
) &
|
||||
SharedProps
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { notFound, redirect } from "next/navigation"
|
||||
import {
|
||||
getPostById,
|
||||
Post,
|
||||
PostWithFilesAndAuthor
|
||||
} from "@lib/server/prisma"
|
||||
import { getPostById, Post, PostWithFilesAndAuthor } from "@lib/server/prisma"
|
||||
import { getCurrentUser } from "@lib/server/session"
|
||||
import ScrollToTop from "@components/scroll-to-top"
|
||||
import { title } from "process"
|
||||
|
|
|
@ -27,7 +27,7 @@ const getPost = async (id: string) => {
|
|||
content: true,
|
||||
updatedAt: true,
|
||||
title: true,
|
||||
html: true,
|
||||
html: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"use client"
|
||||
|
||||
import Button from "@components/button"
|
||||
import ButtonDropdown from "@components/button-dropdown"
|
||||
import { Spinner } from "@components/spinner"
|
||||
import { useToasts } from "@components/toasts"
|
||||
import { Post, User } from "@lib/server/prisma"
|
||||
|
@ -19,7 +18,6 @@ export function UserTable({
|
|||
email: string | null
|
||||
role: string | null
|
||||
displayName: string | null
|
||||
|
||||
}[]
|
||||
}) {
|
||||
const { setToast } = useToasts()
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Spinner } from "@components/spinner"
|
||||
import { getAllPosts, getAllUsers } from "@lib/server/prisma"
|
||||
import { PostTable, UserTable } from "./components/tables"
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import PostList from "@components/post-list"
|
||||
import { getPostsByUser, getUserById } from "@lib/server/prisma"
|
||||
import Image from "next/image"
|
||||
import { Suspense } from "react"
|
||||
import { User } from "react-feather"
|
||||
|
||||
async function PostListWrapper({
|
||||
posts,
|
||||
|
@ -28,15 +30,40 @@ export default async function UserPage({
|
|||
}) {
|
||||
// TODO: the route should be user.name, not id
|
||||
const id = params.username
|
||||
const user = await getUserById(id)
|
||||
const user = await getUserById(id, {
|
||||
image: true
|
||||
})
|
||||
|
||||
const posts = getPostsByUser(id, true)
|
||||
|
||||
const Avatar = () => {
|
||||
if (!user?.image) {
|
||||
return <User />
|
||||
}
|
||||
return (
|
||||
<Image
|
||||
src={user.image}
|
||||
alt="User avatar"
|
||||
className="w-12 h-12 rounded-full"
|
||||
width={48}
|
||||
height={48}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
<h1>Public posts by {user?.displayName || "Anonymous"}</h1>
|
||||
<Avatar />
|
||||
</div>
|
||||
<Suspense fallback={<PostList initialPosts={JSON.stringify({})} />}>
|
||||
{/* @ts-ignore because TS async JSX support is iffy */}
|
||||
{/* @ts-expect-error because TS async JSX support is iffy */}
|
||||
<PostListWrapper posts={posts} userId={id} />
|
||||
</Suspense>
|
||||
</>
|
||||
|
|
|
@ -60,12 +60,10 @@ const Header = () => {
|
|||
)
|
||||
} else if (tab.href) {
|
||||
return (
|
||||
<Link
|
||||
key={tab.value}
|
||||
href={tab.href}
|
||||
data-tab={tab.value}
|
||||
>
|
||||
<Button className={activeStyle} iconLeft={tab.icon}>{tab.name ? tab.name : undefined}</Button>
|
||||
<Link key={tab.value} href={tab.href} data-tab={tab.value}>
|
||||
<Button className={activeStyle} iconLeft={tab.icon}>
|
||||
{tab.name ? tab.name : undefined}
|
||||
</Button>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -129,7 +129,6 @@ const ListItem = ({
|
|||
<li key={file.id}>
|
||||
<Link colored href={`/post/${post.id}#${file.title}`}>
|
||||
{getIconFromFilename(file.title)}
|
||||
|
||||
{file.title || "Untitled file"}
|
||||
</Link>
|
||||
</li>
|
||||
|
|
|
@ -33,3 +33,9 @@
|
|||
gap: var(--gap-half);
|
||||
margin-bottom: var(--gap);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container ul {
|
||||
padding: 0 var(--gap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ import styles from "./skeleton.module.css"
|
|||
export default function Skeleton({
|
||||
width = 100,
|
||||
height = 24,
|
||||
borderRadius = 4,
|
||||
borderRadius = 4
|
||||
}: {
|
||||
width?: number | string
|
||||
height?: number | string,
|
||||
height?: number | string
|
||||
borderRadius?: number | string
|
||||
}) {
|
||||
return <div className={styles.skeleton} style={{ width, height, borderRadius }} />
|
||||
return (
|
||||
<div className={styles.skeleton} style={{ width, height, borderRadius }} />
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"use client";
|
||||
"use client"
|
||||
import Toast, { Toaster } from "react-hot-toast"
|
||||
|
||||
export type ToastType = "success" | "error" | "loading" | "default"
|
||||
|
|
|
@ -4,9 +4,9 @@ import { Providers } from "./providers"
|
|||
import Page from "@components/page"
|
||||
import { Toasts } from "@components/toasts"
|
||||
import Header from "@components/header"
|
||||
import { Inter } from '@next/font/google';
|
||||
import { Inter } from "@next/font/google"
|
||||
|
||||
const inter = Inter({ subsets: ['latin'], variable: "--inter-font" })
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--inter-font" })
|
||||
|
||||
interface RootLayoutProps {
|
||||
children: React.ReactNode
|
||||
|
|
|
@ -5,3 +5,43 @@
|
|||
max-width: 300px;
|
||||
margin-top: var(--gap);
|
||||
}
|
||||
|
||||
/* <div className={styles.upload}>
|
||||
<input
|
||||
type="file"
|
||||
disabled={imageViaOauth}
|
||||
className={styles.uploadInput}
|
||||
/>
|
||||
<Button type="button" disabled={imageViaOauth} width="100%" className={styles.uploadButton}>
|
||||
Upload
|
||||
</Button>
|
||||
</div> */
|
||||
/* we want the file input to be invisible and full width but still interactive button */
|
||||
.upload {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
max-width: 300px;
|
||||
margin-top: var(--gap);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.uploadInput {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
width: 300px;
|
||||
height: 37px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.uploadButton {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* hover should affect button */
|
||||
.uploadInput:hover + button {
|
||||
border: 1px solid var(--fg);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ import Button from "@components/button"
|
|||
import Input from "@components/input"
|
||||
import Note from "@components/note"
|
||||
import { useToasts } from "@components/toasts"
|
||||
import { User } from "next-auth"
|
||||
import { useSession } from "next-auth/react"
|
||||
import { useState } from "react"
|
||||
import styles from "./profile.module.css"
|
||||
|
||||
const Profile = ({ user }: { user: User }) => {
|
||||
// TODO: make this displayName, requires fetching user from DB as session doesnt have it
|
||||
const [name, setName] = useState<string>(user.name || "")
|
||||
const Profile = () => {
|
||||
const { data: session } = useSession()
|
||||
const [name, setName] = useState<string>(session?.user.displayName || "")
|
||||
const [submitting, setSubmitting] = useState<boolean>(false)
|
||||
|
||||
const { setToast } = useToasts()
|
||||
|
@ -31,10 +31,10 @@ const Profile = ({ user }: { user: User }) => {
|
|||
setSubmitting(true)
|
||||
|
||||
const data = {
|
||||
displayName: name,
|
||||
displayName: name
|
||||
}
|
||||
|
||||
const res = await fetch(`/api/user/${user.id}`, {
|
||||
const res = await fetch(`/api/user/${session?.user.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
|
@ -57,6 +57,18 @@ const Profile = ({ user }: { user: User }) => {
|
|||
}
|
||||
}
|
||||
|
||||
/* if we have their email, they signed in with OAuth */
|
||||
// const imageViaOauth = Boolean(session?.user.email)
|
||||
|
||||
// const TooltipComponent = ({ children }: { children: React.ReactNode }) =>
|
||||
// imageViaOauth ? (
|
||||
// <Tooltip content="Change your profile image on your OAuth provider">
|
||||
// {children}
|
||||
// </Tooltip>
|
||||
// ) : (
|
||||
// <>{children}</>
|
||||
// )
|
||||
|
||||
return (
|
||||
<>
|
||||
<Note type="warning">
|
||||
|
@ -83,12 +95,49 @@ const Profile = ({ user }: { user: User }) => {
|
|||
type="email"
|
||||
width={"100%"}
|
||||
placeholder="my@email.io"
|
||||
value={user.email || undefined}
|
||||
value={session?.user.email || undefined}
|
||||
disabled
|
||||
aria-label="Email"
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" loading={submitting}>Submit</Button>
|
||||
{/* <div>
|
||||
<label htmlFor="image">User Avatar</label>
|
||||
{user.image ? (
|
||||
<Input
|
||||
id="image"
|
||||
type="file"
|
||||
width={"100%"}
|
||||
placeholder="my image"
|
||||
disabled
|
||||
aria-label="Image"
|
||||
src={user.image}
|
||||
/>
|
||||
) : (
|
||||
<UserIcon />
|
||||
)}
|
||||
<TooltipComponent>
|
||||
<div className={styles.upload}>
|
||||
<input
|
||||
type="file"
|
||||
disabled={imageViaOauth}
|
||||
className={styles.uploadInput}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={imageViaOauth}
|
||||
width="100%"
|
||||
className={styles.uploadButton}
|
||||
aria-hidden="true"
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
</div>
|
||||
</TooltipComponent>
|
||||
</div> */}
|
||||
|
||||
<Button type="submit" loading={submitting}>
|
||||
Submit
|
||||
</Button>
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -1,19 +1,10 @@
|
|||
import SettingsGroup from "../components/settings-group"
|
||||
import Profile from "app/settings/components/sections/profile"
|
||||
import { authOptions } from "@lib/server/auth"
|
||||
import { getCurrentUser } from "@lib/server/session"
|
||||
import { redirect } from "next/navigation"
|
||||
|
||||
export default async function SettingsPage() {
|
||||
const user = await getCurrentUser()
|
||||
|
||||
if (!user) {
|
||||
return redirect(authOptions.pages?.signIn || "/new")
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsGroup title="Profile">
|
||||
<Profile user={user} />
|
||||
<Profile />
|
||||
</SettingsGroup>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ export const config = (env: Environment): Config => {
|
|||
return value
|
||||
}
|
||||
|
||||
const defaultIfUndefined = (str: string, defaultValue: string): string => {
|
||||
const value = env[str]
|
||||
if (value === undefined) {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
// const defaultIfUndefined = (str: string, defaultValue: string): string => {
|
||||
// const value = env[str]
|
||||
// if (value === undefined) {
|
||||
// return defaultValue
|
||||
// }
|
||||
// return value
|
||||
// }
|
||||
|
||||
const validNodeEnvs = (str: EnvironmentValue) => {
|
||||
const valid = ["development", "production", "test"]
|
||||
|
@ -56,14 +56,6 @@ export const config = (env: Environment): Config => {
|
|||
|
||||
const is_production = env.NODE_ENV === "production"
|
||||
|
||||
const developmentDefault = (name: string, defaultValue: string): string => {
|
||||
if (is_production) {
|
||||
return throwIfUndefined(name)
|
||||
} else {
|
||||
return defaultIfUndefined(name, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
validNodeEnvs(env.NODE_ENV)
|
||||
|
||||
throwIfUndefined("DATABASE_URL")
|
||||
|
|
|
@ -22,7 +22,7 @@ interface File {
|
|||
export interface GistResponse {
|
||||
id: string
|
||||
created_at: Timestamp
|
||||
description: String
|
||||
description: string
|
||||
files: {
|
||||
[key: string]: File
|
||||
}
|
||||
|
|
2
src/lib/gist/types.d.ts
vendored
2
src/lib/gist/types.d.ts
vendored
|
@ -6,6 +6,6 @@ export interface GistFile {
|
|||
export interface Gist {
|
||||
id: string
|
||||
created_at: Date
|
||||
description: String
|
||||
description: string
|
||||
files: GistFile[]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useRef, useEffect } from "react"
|
||||
|
||||
function useTraceUpdate(props: { [key: string]: any }) {
|
||||
function useTraceUpdate(props: { [key: string]: unknown }) {
|
||||
const prev = useRef(props)
|
||||
useEffect(() => {
|
||||
const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
|
||||
|
@ -8,7 +8,7 @@ function useTraceUpdate(props: { [key: string]: any }) {
|
|||
ps[k] = [prev.current[k], v]
|
||||
}
|
||||
return ps
|
||||
}, {} as { [key: string]: any })
|
||||
}, {} as { [key: string]: unknown })
|
||||
if (Object.keys(changedProps).length > 0) {
|
||||
console.log("Changed props:", changedProps)
|
||||
}
|
||||
|
|
|
@ -5,10 +5,9 @@ import CredentialsProvider from "next-auth/providers/credentials"
|
|||
import { prisma } from "@lib/server/prisma"
|
||||
import config from "@lib/config"
|
||||
import * as crypto from "crypto"
|
||||
import { Provider } from "next-auth/providers"
|
||||
|
||||
const credentialsOptions = () => {
|
||||
const options: Record<string, any> = {
|
||||
const options: Record<string, unknown> = {
|
||||
username: {
|
||||
label: "Username",
|
||||
required: true,
|
||||
|
@ -47,7 +46,8 @@ const providers = () => {
|
|||
providers.push(
|
||||
CredentialsProvider({
|
||||
name: "Drift",
|
||||
credentials: credentialsOptions(),
|
||||
// @ts-expect-error TODO: fix types
|
||||
credentials: credentialsOptions() as unknown,
|
||||
async authorize(credentials) {
|
||||
if (!credentials || !credentials.username || !credentials.password) {
|
||||
throw new Error("Missing credentials")
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var prisma: PrismaClient | undefined
|
||||
}
|
||||
|
||||
import config from "@lib/config"
|
||||
import { Post, PrismaClient, File, User, Prisma } from "@prisma/client"
|
||||
import { Post, PrismaClient, User, Prisma } from "@prisma/client"
|
||||
export type { User, File, Post } from "@prisma/client"
|
||||
|
||||
export const prisma =
|
||||
|
@ -126,7 +127,7 @@ export async function getPostsByUser(userId: User["id"], withFiles?: boolean) {
|
|||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
createdAt: true,
|
||||
createdAt: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -136,7 +137,10 @@ export async function getPostsByUser(userId: User["id"], withFiles?: boolean) {
|
|||
return posts
|
||||
}
|
||||
|
||||
export const getUserById = async (userId: User["id"]) => {
|
||||
export const getUserById = async (
|
||||
userId: User["id"],
|
||||
selects?: Prisma.UserFindUniqueArgs["select"]
|
||||
) => {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: userId
|
||||
|
@ -146,7 +150,8 @@ export const getUserById = async (userId: User["id"]) => {
|
|||
email: true,
|
||||
// displayName: true,
|
||||
role: true,
|
||||
displayName: true
|
||||
displayName: true,
|
||||
...selects
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -199,7 +204,7 @@ export const getPostById = async (
|
|||
postId: Post["id"],
|
||||
options?: GetPostByIdOptions
|
||||
): Promise<Post | PostWithFiles | PostWithFilesAndAuthor | null> => {
|
||||
let post = await prisma.post.findUnique({
|
||||
const post = await prisma.post.findUnique({
|
||||
where: {
|
||||
id: postId
|
||||
},
|
||||
|
|
|
@ -11,7 +11,7 @@ const epochs = [
|
|||
] as const
|
||||
|
||||
const getDuration = (timeAgoInSeconds: number) => {
|
||||
for (let [name, seconds] of epochs) {
|
||||
for (const [name, seconds] of epochs) {
|
||||
const interval = Math.floor(timeAgoInSeconds / seconds)
|
||||
|
||||
if (interval >= 1) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"dev": "next dev --port 3000",
|
||||
"build": "next build",
|
||||
"start": "next start --port 3000",
|
||||
"lint": "next lint && prettier --list-different --config .prettierrc '{components,lib,app}/**/*.{ts,tsx}' --write",
|
||||
"lint": "next lint && prettier --list-different --config .prettierrc '{components,lib,app,pages}/**/*.{ts,tsx}' --write",
|
||||
"analyze": "cross-env ANALYZE=true next build",
|
||||
"find:unused": "next-unused",
|
||||
"prisma": "prisma",
|
||||
|
@ -51,6 +51,8 @@
|
|||
"@types/react-datepicker": "4.4.1",
|
||||
"@types/react-dom": "18.0.3",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
||||
"@typescript-eslint/parser": "^5.46.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cross-env": "7.0.3",
|
||||
"csstype": "^3.1.1",
|
||||
|
|
|
@ -45,13 +45,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
switch (req.method) {
|
||||
case "GET":
|
||||
switch (action) {
|
||||
case "users":
|
||||
case "users": {
|
||||
const users = await prisma.user.findMany()
|
||||
return res.status(200).json(users)
|
||||
case "posts":
|
||||
}
|
||||
case "posts": {
|
||||
const posts = await prisma.post.findMany()
|
||||
return res.status(200).json(posts)
|
||||
case "user":
|
||||
}
|
||||
case "user": {
|
||||
const { id: userId } = req.query
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
|
@ -59,7 +61,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
}
|
||||
})
|
||||
return res.status(200).json(user)
|
||||
case "post":
|
||||
}
|
||||
case "post": {
|
||||
const { id: postId } = req.query
|
||||
const post = await prisma.post.findUnique({
|
||||
where: {
|
||||
|
@ -68,10 +71,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
})
|
||||
return res.status(200).json(post)
|
||||
}
|
||||
}
|
||||
break
|
||||
case "PATCH":
|
||||
switch (action) {
|
||||
case "set-role":
|
||||
case "set-role": {
|
||||
const { userId, role } = req.body
|
||||
if (!userId || !role || role !== "admin" || role !== "user") {
|
||||
return res.status(400).json({ error: "Invalid request" })
|
||||
|
@ -86,10 +90,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
return res.status(200).json(user)
|
||||
}
|
||||
}
|
||||
break
|
||||
case "DELETE":
|
||||
switch (action) {
|
||||
case "delete-user":
|
||||
case "delete-user": {
|
||||
const { userId } = req.body
|
||||
if (!userId) {
|
||||
return res.status(400).json({ error: "Invalid request" })
|
||||
|
@ -98,7 +103,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
await deleteUser(userId)
|
||||
|
||||
return res.status(200).send("User deleted")
|
||||
case "delete-post":
|
||||
}
|
||||
case "delete-post": {
|
||||
const { postId } = req.body
|
||||
if (!postId) {
|
||||
return res.status(400).json({ error: "Invalid request" })
|
||||
|
@ -110,6 +116,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
return res.status(200).json(post)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ export default async function requiresPasscode(
|
|||
if (slug === "requires-passcode") {
|
||||
return handleRequiresPasscode(req, res)
|
||||
}
|
||||
|
||||
return res.status(404).json({ error: "Not found" })
|
||||
default:
|
||||
return res.status(405).json({ error: "Method not allowed" })
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { NextApiRequest, NextApiResponse } from "next"
|
||||
import {prisma} from "lib/server/prisma"
|
||||
import { prisma } from "lib/server/prisma"
|
||||
import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||
|
||||
const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { withMethods } from "@lib/api-middleware/with-methods"
|
||||
import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||
import { getPostById, PostWithFiles } from "@lib/server/prisma"
|
||||
import { getPostById } from "@lib/server/prisma"
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
import { getSession } from "next-auth/react"
|
||||
import { prisma } from "lib/server/prisma"
|
||||
|
@ -14,7 +14,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
export default withMethods(["GET", "PUT", "DELETE"], handler)
|
||||
|
||||
async function handleGet(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
async function handleGet(req: NextApiRequest, res: NextApiResponse<unknown>) {
|
||||
const id = parseQueryParam(req.query.id)
|
||||
|
||||
if (!id) {
|
||||
|
@ -44,7 +44,7 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||
// the user can always go directly to their own post
|
||||
if (session?.user.id === post.authorId) {
|
||||
return res.json({
|
||||
...post,
|
||||
...post
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||
|
||||
if (hash === post.password) {
|
||||
return res.json({
|
||||
...post,
|
||||
...post
|
||||
})
|
||||
} else {
|
||||
return {
|
||||
|
@ -76,7 +76,7 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||
}
|
||||
|
||||
// PUT is for adjusting visibility and password
|
||||
async function handlePut(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
async function handlePut(req: NextApiRequest, res: NextApiResponse<unknown>) {
|
||||
const { password, visibility } = req.body
|
||||
const id = parseQueryParam(req.query.id)
|
||||
|
||||
|
@ -124,7 +124,10 @@ async function handlePut(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||
})
|
||||
}
|
||||
|
||||
async function handleDelete(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
async function handleDelete(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<unknown>
|
||||
) {
|
||||
const id = parseQueryParam(req.query.id)
|
||||
|
||||
if (!id) {
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
// nextjs typescript api handler
|
||||
|
||||
import { withMethods } from "@lib/api-middleware/with-methods"
|
||||
|
||||
import { authOptions } from "@lib/server/auth"
|
||||
import { prisma, getPostById } from "@lib/server/prisma"
|
||||
import { prisma } from "@lib/server/prisma"
|
||||
import { NextApiRequest, NextApiResponse } from "next"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { File } from "@lib/server/prisma"
|
||||
import * as crypto from "crypto"
|
||||
import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file"
|
||||
import { getSession } from "next-auth/react"
|
||||
import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return await handlePost(req, res)
|
||||
|
@ -18,7 +14,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
export default withMethods(["POST"], handler)
|
||||
|
||||
async function handlePost(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
async function handlePost(req: NextApiRequest, res: NextApiResponse<unknown>) {
|
||||
try {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
if (!session || !session.user.id) {
|
||||
|
@ -49,7 +45,7 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||
throw new Error("You must submit at least one file")
|
||||
}
|
||||
|
||||
let hashedPassword: string = ""
|
||||
let hashedPassword = ""
|
||||
if (req.body.visibility === "protected") {
|
||||
hashedPassword = crypto
|
||||
.createHash("sha256")
|
||||
|
|
|
@ -20,7 +20,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
let posts: ServerPostWithFiles[]
|
||||
if (session?.user.id === user || session?.user.role === "admin") {
|
||||
posts = await searchPosts(query, {
|
||||
userId: user,
|
||||
userId: user
|
||||
})
|
||||
} else {
|
||||
posts = await searchPosts(query, {
|
||||
|
|
|
@ -23,7 +23,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
}
|
||||
|
||||
switch (req.method) {
|
||||
case "PUT":
|
||||
case "PUT": {
|
||||
const { displayName } = req.body
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: {
|
||||
|
@ -40,6 +40,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
name: updatedUser.displayName
|
||||
// bio: updatedUser.bio
|
||||
})
|
||||
}
|
||||
case "GET":
|
||||
return res.json(currUser)
|
||||
case "DELETE":
|
||||
|
@ -48,7 +49,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
}
|
||||
|
||||
await deleteUser(id)
|
||||
|
||||
break
|
||||
default:
|
||||
return res.status(405).json({ message: "Method not allowed" })
|
||||
}
|
||||
|
@ -61,7 +62,6 @@ export default withMethods(["GET", "PUT", "DELETE"], handler)
|
|||
* @warning This function does not perform any authorization checks
|
||||
*/
|
||||
export async function deleteUser(id: string | undefined) {
|
||||
|
||||
// first delete all of the user's posts
|
||||
await prisma.post.deleteMany({
|
||||
where: {
|
||||
|
|
|
@ -7,7 +7,7 @@ export default async function handle(
|
|||
res: NextApiResponse
|
||||
) {
|
||||
switch (req.method) {
|
||||
case "GET":
|
||||
case "GET": {
|
||||
const userId = parseQueryParam(req.query.userId)
|
||||
if (!userId) {
|
||||
return res.status(400).json({ error: "Missing userId" })
|
||||
|
@ -15,6 +15,7 @@ export default async function handle(
|
|||
|
||||
const posts = await getPostsByUser(userId)
|
||||
return res.json(posts)
|
||||
}
|
||||
default:
|
||||
return res.status(405).end()
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ specifiers:
|
|||
'@types/react-datepicker': 4.4.1
|
||||
'@types/react-dom': 18.0.3
|
||||
'@types/uuid': ^9.0.0
|
||||
'@typescript-eslint/eslint-plugin': ^5.46.1
|
||||
'@typescript-eslint/parser': ^5.46.1
|
||||
'@wcj/markdown-to-html': ^2.1.2
|
||||
'@wits/next-themes': 0.2.14
|
||||
client-only: ^0.0.1
|
||||
|
@ -90,6 +92,8 @@ devDependencies:
|
|||
'@types/react-datepicker': 4.4.1_biqbaboplfbrettd7655fr4n2y
|
||||
'@types/react-dom': 18.0.3
|
||||
'@types/uuid': 9.0.0
|
||||
'@typescript-eslint/eslint-plugin': 5.46.1_byqm7zzsgtndvuamqqta6vngru
|
||||
'@typescript-eslint/parser': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
clsx: 1.2.1
|
||||
cross-env: 7.0.3
|
||||
csstype: 3.1.1
|
||||
|
@ -1509,6 +1513,10 @@ packages:
|
|||
'@types/istanbul-lib-report': 3.0.0
|
||||
dev: false
|
||||
|
||||
/@types/json-schema/7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
dev: true
|
||||
|
||||
/@types/json5/0.0.29:
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
dev: true
|
||||
|
@ -1583,6 +1591,10 @@ packages:
|
|||
/@types/scheduler/0.16.2:
|
||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||
|
||||
/@types/semver/7.3.13:
|
||||
resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
|
||||
dev: true
|
||||
|
||||
/@types/stack-utils/2.0.1:
|
||||
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
|
||||
dev: false
|
||||
|
@ -1605,8 +1617,35 @@ packages:
|
|||
'@types/yargs-parser': 21.0.0
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/parser/5.42.1_hsmo2rtalirsvadpuxki35bq2i:
|
||||
resolution: {integrity: sha512-kAV+NiNBWVQDY9gDJDToTE/NO8BHi4f6b7zTsVAJoTkmB/zlfOpiEVBzHOKtlgTndCKe8vj9F/PuolemZSh50Q==}
|
||||
/@typescript-eslint/eslint-plugin/5.46.1_byqm7zzsgtndvuamqqta6vngru:
|
||||
resolution: {integrity: sha512-YpzNv3aayRBwjs4J3oz65eVLXc9xx0PDbIRisHj+dYhvBn02MjYOD96P8YGiWEIFBrojaUjxvkaUpakD82phsA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^5.0.0
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
'@typescript-eslint/scope-manager': 5.46.1
|
||||
'@typescript-eslint/type-utils': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
'@typescript-eslint/utils': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
debug: 4.3.4
|
||||
eslint: 8.27.0
|
||||
ignore: 5.2.0
|
||||
natural-compare-lite: 1.4.0
|
||||
regexpp: 3.2.0
|
||||
semver: 7.3.8
|
||||
tsutils: 3.21.0_typescript@4.6.4
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/parser/5.46.1_hsmo2rtalirsvadpuxki35bq2i:
|
||||
resolution: {integrity: sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
|
@ -1615,9 +1654,9 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 5.42.1
|
||||
'@typescript-eslint/types': 5.42.1
|
||||
'@typescript-eslint/typescript-estree': 5.42.1_typescript@4.6.4
|
||||
'@typescript-eslint/scope-manager': 5.46.1
|
||||
'@typescript-eslint/types': 5.46.1
|
||||
'@typescript-eslint/typescript-estree': 5.46.1_typescript@4.6.4
|
||||
debug: 4.3.4
|
||||
eslint: 8.27.0
|
||||
typescript: 4.6.4
|
||||
|
@ -1625,12 +1664,32 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/scope-manager/5.42.1:
|
||||
resolution: {integrity: sha512-QAZY/CBP1Emx4rzxurgqj3rUinfsh/6mvuKbLNMfJMMKYLRBfweus8brgXF8f64ABkIZ3zdj2/rYYtF8eiuksQ==}
|
||||
/@typescript-eslint/scope-manager/5.46.1:
|
||||
resolution: {integrity: sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 5.42.1
|
||||
'@typescript-eslint/visitor-keys': 5.42.1
|
||||
'@typescript-eslint/types': 5.46.1
|
||||
'@typescript-eslint/visitor-keys': 5.46.1
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/type-utils/5.46.1_hsmo2rtalirsvadpuxki35bq2i:
|
||||
resolution: {integrity: sha512-V/zMyfI+jDmL1ADxfDxjZ0EMbtiVqj8LUGPAGyBkXXStWmCUErMpW873zEHsyguWCuq2iN4BrlWUkmuVj84yng==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: '*'
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 5.46.1_typescript@4.6.4
|
||||
'@typescript-eslint/utils': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
debug: 4.3.4
|
||||
eslint: 8.27.0
|
||||
tsutils: 3.21.0_typescript@4.6.4
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/types/4.33.0:
|
||||
|
@ -1638,8 +1697,8 @@ packages:
|
|||
engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1}
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/types/5.42.1:
|
||||
resolution: {integrity: sha512-Qrco9dsFF5lhalz+lLFtxs3ui1/YfC6NdXu+RAGBa8uSfn01cjO7ssCsjIsUs484vny9Xm699FSKwpkCcqwWwA==}
|
||||
/@typescript-eslint/types/5.46.1:
|
||||
resolution: {integrity: sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
|
@ -1664,8 +1723,8 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/typescript-estree/5.42.1_typescript@4.6.4:
|
||||
resolution: {integrity: sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==}
|
||||
/@typescript-eslint/typescript-estree/5.46.1_typescript@4.6.4:
|
||||
resolution: {integrity: sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
|
@ -1673,8 +1732,8 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 5.42.1
|
||||
'@typescript-eslint/visitor-keys': 5.42.1
|
||||
'@typescript-eslint/types': 5.46.1
|
||||
'@typescript-eslint/visitor-keys': 5.46.1
|
||||
debug: 4.3.4
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
|
@ -1685,6 +1744,26 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/utils/5.46.1_hsmo2rtalirsvadpuxki35bq2i:
|
||||
resolution: {integrity: sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.11
|
||||
'@types/semver': 7.3.13
|
||||
'@typescript-eslint/scope-manager': 5.46.1
|
||||
'@typescript-eslint/types': 5.46.1
|
||||
'@typescript-eslint/typescript-estree': 5.46.1_typescript@4.6.4
|
||||
eslint: 8.27.0
|
||||
eslint-scope: 5.1.1
|
||||
eslint-utils: 3.0.0_eslint@8.27.0
|
||||
semver: 7.3.8
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/visitor-keys/4.33.0:
|
||||
resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==}
|
||||
engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1}
|
||||
|
@ -1693,11 +1772,11 @@ packages:
|
|||
eslint-visitor-keys: 2.1.0
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/visitor-keys/5.42.1:
|
||||
resolution: {integrity: sha512-LOQtSF4z+hejmpUvitPlc4hA7ERGoj2BVkesOcG91HCn8edLGUXbTrErmutmPbl8Bo9HjAvOO/zBKQHExXNA2A==}
|
||||
/@typescript-eslint/visitor-keys/5.46.1:
|
||||
resolution: {integrity: sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 5.42.1
|
||||
'@typescript-eslint/types': 5.46.1
|
||||
eslint-visitor-keys: 3.3.0
|
||||
dev: true
|
||||
|
||||
|
@ -2780,11 +2859,11 @@ packages:
|
|||
dependencies:
|
||||
'@next/eslint-plugin-next': 13.0.3
|
||||
'@rushstack/eslint-patch': 1.2.0
|
||||
'@typescript-eslint/parser': 5.42.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
'@typescript-eslint/parser': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
eslint: 8.27.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-import-resolver-typescript: 2.7.1_dcpv4nbdr5ks2h5677xdltrk6e
|
||||
eslint-plugin-import: 2.26.0_fjrawv2a4e2kreqduevmayjdry
|
||||
eslint-plugin-import: 2.26.0_gqysc5ehwyt3mg2jls3nr3332q
|
||||
eslint-plugin-jsx-a11y: 6.6.1_eslint@8.27.0
|
||||
eslint-plugin-react: 7.31.10_eslint@8.27.0
|
||||
eslint-plugin-react-hooks: 4.6.0_eslint@8.27.0
|
||||
|
@ -2812,7 +2891,7 @@ packages:
|
|||
dependencies:
|
||||
debug: 4.3.4
|
||||
eslint: 8.27.0
|
||||
eslint-plugin-import: 2.26.0_fjrawv2a4e2kreqduevmayjdry
|
||||
eslint-plugin-import: 2.26.0_gqysc5ehwyt3mg2jls3nr3332q
|
||||
glob: 7.2.3
|
||||
is-glob: 4.0.3
|
||||
resolve: 1.22.1
|
||||
|
@ -2821,7 +2900,7 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils/2.7.4_c5vbubjxm3sqe7zyydgtitlaga:
|
||||
/eslint-module-utils/2.7.4_nw56cc7ve4sv3zakvubomgge2q:
|
||||
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
|
@ -2842,7 +2921,7 @@ packages:
|
|||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.42.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
'@typescript-eslint/parser': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
debug: 3.2.7
|
||||
eslint: 8.27.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
|
@ -2851,7 +2930,7 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.26.0_fjrawv2a4e2kreqduevmayjdry:
|
||||
/eslint-plugin-import/2.26.0_gqysc5ehwyt3mg2jls3nr3332q:
|
||||
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
|
@ -2861,14 +2940,14 @@ packages:
|
|||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.42.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
'@typescript-eslint/parser': 5.46.1_hsmo2rtalirsvadpuxki35bq2i
|
||||
array-includes: 3.1.6
|
||||
array.prototype.flat: 1.3.1
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.27.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.4_c5vbubjxm3sqe7zyydgtitlaga
|
||||
eslint-module-utils: 2.7.4_nw56cc7ve4sv3zakvubomgge2q
|
||||
has: 1.0.3
|
||||
is-core-module: 2.11.0
|
||||
is-glob: 4.0.3
|
||||
|
@ -2936,6 +3015,14 @@ packages:
|
|||
string.prototype.matchall: 4.0.8
|
||||
dev: true
|
||||
|
||||
/eslint-scope/5.1.1:
|
||||
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
esrecurse: 4.3.0
|
||||
estraverse: 4.3.0
|
||||
dev: true
|
||||
|
||||
/eslint-scope/7.1.1:
|
||||
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
@ -3040,6 +3127,11 @@ packages:
|
|||
estraverse: 5.3.0
|
||||
dev: true
|
||||
|
||||
/estraverse/4.3.0:
|
||||
resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
|
||||
engines: {node: '>=4.0'}
|
||||
dev: true
|
||||
|
||||
/estraverse/5.3.0:
|
||||
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
@ -5102,6 +5194,10 @@ packages:
|
|||
dev: false
|
||||
optional: true
|
||||
|
||||
/natural-compare-lite/1.4.0:
|
||||
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
||||
dev: true
|
||||
|
||||
/natural-compare/1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
|
|
Loading…
Reference in a new issue