dep management
This commit is contained in:
parent
ecd4521403
commit
733a93dd87
17 changed files with 15 additions and 2214 deletions
|
@ -2,7 +2,6 @@ import { Button, ButtonGroup, Loading, useToasts } from "@geist-ui/core/dist"
|
||||||
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import type { PostVisibility } from "@lib/types"
|
import type { PostVisibility } from "@lib/types"
|
||||||
import PasswordModal from "@components/password-modal"
|
import PasswordModal from "@components/password-modal"
|
||||||
import { getCookie } from "cookies-next"
|
|
||||||
import { useCallback, useState } from "react"
|
import { useCallback, useState } from "react"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { MDXRemote, MDXRemoteProps } from "next-mdx-remote";
|
|
||||||
|
|
||||||
export default function MDXRemoteWrapper(props: MDXRemoteProps) {
|
|
||||||
return <MDXRemote {...props} />;
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ import { ChangeEvent, useCallback, useEffect, useState } from "react"
|
||||||
import useDebounce from "@lib/hooks/use-debounce"
|
import useDebounce from "@lib/hooks/use-debounce"
|
||||||
import Link from "@components/link"
|
import Link from "@components/link"
|
||||||
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import { getCookie } from "cookies-next"
|
|
||||||
import type { PostWithFiles } from "@lib/server/prisma"
|
import type { PostWithFiles } from "@lib/server/prisma"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -34,7 +33,6 @@ const PostList = ({ morePosts, initialPosts }: Props) => {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`,
|
|
||||||
"x-page": `${posts.length / 10 + 1}`
|
"x-page": `${posts.length / 10 + 1}`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -63,7 +61,6 @@ const PostList = ({ morePosts, initialPosts }: Props) => {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
|
||||||
// "tok": process.env.SECRET_KEY || ''
|
// "tok": process.env.SECRET_KEY || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +96,6 @@ const PostList = ({ morePosts, initialPosts }: Props) => {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { Input, Button, useToasts } from "@geist-ui/core/dist"
|
import { Input, Button, useToasts } from "@geist-ui/core/dist"
|
||||||
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import { getCookie } from "cookies-next"
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
const Password = () => {
|
const Password = () => {
|
||||||
|
@ -46,7 +45,6 @@ const Password = () => {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
oldPassword: password,
|
oldPassword: password,
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { Note, Input, Textarea, Button, useToasts } from "@geist-ui/core/dist"
|
import { Note, Input, Textarea, Button, useToasts } from "@geist-ui/core/dist"
|
||||||
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
import { TOKEN_COOKIE_NAME } from "@lib/constants"
|
||||||
import { getCookie } from "cookies-next"
|
|
||||||
import { User } from "next-auth"
|
import { User } from "next-auth"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
|
@ -45,7 +44,6 @@ const Profile = ({ user }: { user: User }) => {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${getCookie(TOKEN_COOKIE_NAME)}`
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
import type { NextApiHandler, NextApiRequest, NextApiResponse } from "next"
|
|
||||||
import * as z from "zod"
|
|
||||||
import type { ZodSchema, ZodType } from "zod"
|
|
||||||
|
|
||||||
type NextApiRequestWithParsedBody<T> = NextApiRequest & {
|
|
||||||
parsedBody?: T
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NextApiHandlerWithParsedBody<T> = (
|
|
||||||
req: NextApiRequestWithParsedBody<T>,
|
|
||||||
res: NextApiResponse
|
|
||||||
) => ReturnType<NextApiHandler>
|
|
||||||
|
|
||||||
export function withValidation<T extends ZodSchema>(
|
|
||||||
schema: T,
|
|
||||||
handler: NextApiHandler
|
|
||||||
): (
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse
|
|
||||||
) => Promise<void | NextApiResponse<any> | NextApiHandlerWithParsedBody<T>> {
|
|
||||||
return async function (req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
const body = req.body
|
|
||||||
|
|
||||||
await schema.parseAsync(body)
|
|
||||||
|
|
||||||
;(req as NextApiRequestWithParsedBody<T>).parsedBody = body
|
|
||||||
|
|
||||||
return handler(req, res) as Promise<NextApiHandlerWithParsedBody<T>>
|
|
||||||
} catch (error) {
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
if (error instanceof z.ZodError) {
|
|
||||||
return res.status(422).json(error.issues)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(422).end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
// next api route jwt middleware; check if the user has a valid jwt token
|
|
||||||
|
|
||||||
import config from "@lib/config"
|
|
||||||
import { User } from "@prisma/client"
|
|
||||||
import { prisma } from "@lib/server/prisma"
|
|
||||||
import * as jwt from "jsonwebtoken"
|
|
||||||
import next, { NextApiHandler, NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
type ReqWithUser = NextApiRequest & {
|
|
||||||
user?: User
|
|
||||||
}
|
|
||||||
|
|
||||||
type WrappedHandler = (req: ReqWithUser, res: NextApiResponse) => Promise<void>
|
|
||||||
|
|
||||||
// usage: useJwt(otherHandler)
|
|
||||||
|
|
||||||
// we want the usage to be the user writing their API route and exporting it with useJwt(handler)
|
|
||||||
|
|
||||||
// uses prisma
|
|
||||||
export async function withJwt(
|
|
||||||
origHandler: NextApiHandler
|
|
||||||
): Promise<WrappedHandler | void> {
|
|
||||||
return async (req: ReqWithUser, res: NextApiResponse) => {
|
|
||||||
const authHeader = req ? req.headers["authorization"] : undefined
|
|
||||||
const token = authHeader && authHeader.split(" ")[1]
|
|
||||||
|
|
||||||
if (token == null) return res.status(401).send("Unauthorized")
|
|
||||||
|
|
||||||
const authToken = await prisma.authTokens.findUnique({
|
|
||||||
// @ts-ignore
|
|
||||||
where: { id: token }
|
|
||||||
})
|
|
||||||
if (authToken == null) {
|
|
||||||
return res.status(401).send("Unauthorized")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authToken.deletedAt) {
|
|
||||||
return res.status(401).json({
|
|
||||||
message: "Token is no longer valid"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
jwt.verify(token, config.jwt_secret, async (err: any, user: any) => {
|
|
||||||
if (err) return res.status(403).send("Forbidden")
|
|
||||||
const userObj = await prisma.user.findUnique({
|
|
||||||
where: { id: user.id },
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
// displayName: true,
|
|
||||||
// bio: true,
|
|
||||||
// createdAt: true,
|
|
||||||
// updatedAt: true,
|
|
||||||
// deletedAt: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!userObj) {
|
|
||||||
return res.status(403).send("Forbidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
;(req as ReqWithUser).user = user
|
|
||||||
return origHandler(req, res)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { USER_COOKIE_NAME, TOKEN_COOKIE_NAME } from "@lib/constants"
|
|
||||||
import { User } from "@lib/server/prisma"
|
|
||||||
import { setCookie } from "cookies-next"
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
import { generateAndExpireAccessToken } from "./generate-access-token"
|
|
||||||
|
|
||||||
export const signin = async (
|
|
||||||
userId: User["id"],
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse
|
|
||||||
) => {
|
|
||||||
const token = await generateAndExpireAccessToken(userId)
|
|
||||||
setCookie(USER_COOKIE_NAME, userId, {
|
|
||||||
maxAge: 30 * 24 * 60 * 60, // 30 days,
|
|
||||||
req,
|
|
||||||
res
|
|
||||||
})
|
|
||||||
setCookie(TOKEN_COOKIE_NAME, token, {
|
|
||||||
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
||||||
req,
|
|
||||||
res
|
|
||||||
})
|
|
||||||
|
|
||||||
return token
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { z } from "zod"
|
|
||||||
|
|
||||||
export const CreatePostSchema = z.object({
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
files: z.array(z.object({
|
|
||||||
title: z.string(),
|
|
||||||
content: z.string(),
|
|
||||||
})),
|
|
||||||
visibility: z.string(),
|
|
||||||
password: z.string().optional(),
|
|
||||||
expiresAt: z.number().optional().nullish(),
|
|
||||||
parentId: z.string().optional()
|
|
||||||
})
|
|
||||||
|
|
||||||
export const DeletePostSchema = z.object({
|
|
||||||
id: z.string()
|
|
||||||
})
|
|
|
@ -1,8 +1,5 @@
|
||||||
import dotenv from "dotenv"
|
|
||||||
import bundleAnalyzer from "@next/bundle-analyzer"
|
import bundleAnalyzer from "@next/bundle-analyzer"
|
||||||
|
|
||||||
dotenv.config()
|
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
|
|
@ -14,27 +14,15 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@geist-ui/core": "^2.3.8",
|
"@geist-ui/core": "^2.3.8",
|
||||||
"@geist-ui/icons": "1.0.2",
|
"@geist-ui/icons": "1.0.2",
|
||||||
"@mdx-js/loader": "^2.1.5",
|
|
||||||
"@mdx-js/mdx": "^2.1.5",
|
|
||||||
"@mdx-js/react": "^2.1.5",
|
|
||||||
"@next-auth/prisma-adapter": "^1.0.5",
|
"@next-auth/prisma-adapter": "^1.0.5",
|
||||||
"@prisma/client": "^4.6.1",
|
"@prisma/client": "^4.6.1",
|
||||||
"@types/prismjs": "^1.26.0",
|
|
||||||
"@wcj/markdown-to-html": "^2.1.2",
|
"@wcj/markdown-to-html": "^2.1.2",
|
||||||
"bcrypt": "^5.1.0",
|
"bcrypt": "^5.1.0",
|
||||||
"client-zip": "2.2.1",
|
"client-zip": "2.2.1",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"cookies-next": "^2.1.1",
|
|
||||||
"dotenv": "16.0.0",
|
|
||||||
"jsonwebtoken": "^8.5.1",
|
|
||||||
"marked": "^4.2.2",
|
|
||||||
"next": "13.0.3-canary.4",
|
"next": "13.0.3-canary.4",
|
||||||
"next-auth": "^4.16.4",
|
"next-auth": "^4.16.4",
|
||||||
"next-joi": "^2.2.1",
|
|
||||||
"next-mdx-remote": "^4.2.0",
|
|
||||||
"next-themes": "npm:@wits/next-themes@0.2.7",
|
"next-themes": "npm:@wits/next-themes@0.2.7",
|
||||||
"prism-react-renderer": "^1.3.5",
|
|
||||||
"prismjs": "^1.29.0",
|
|
||||||
"rc-table": "7.24.1",
|
"rc-table": "7.24.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-datepicker": "4.8.0",
|
"react-datepicker": "4.8.0",
|
||||||
|
@ -42,31 +30,17 @@
|
||||||
"react-dropzone": "14.2.3",
|
"react-dropzone": "14.2.3",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
"react-loading-skeleton": "3.1.0",
|
"react-loading-skeleton": "3.1.0",
|
||||||
"rehype-parse": "^8.0.4",
|
|
||||||
"rehype-remark": "^9.1.2",
|
|
||||||
"remark": "^14.0.2",
|
|
||||||
"remark-gfm": "^3.0.1",
|
|
||||||
"remark-html": "^15.0.1",
|
|
||||||
"remark-mdx": "^2.1.5",
|
|
||||||
"remark-rehype": "^10.1.0",
|
|
||||||
"remark-stringify": "^10.0.2",
|
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"showdown": "^2.1.0",
|
|
||||||
"swr": "1.3.0",
|
"swr": "1.3.0",
|
||||||
"textarea-markdown-editor": "0.1.13",
|
"textarea-markdown-editor": "0.1.13"
|
||||||
"unified": "^10.1.2",
|
|
||||||
"zod": "^3.19.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next/bundle-analyzer": "12.1.6",
|
"@next/bundle-analyzer": "12.1.6",
|
||||||
"@types/bcrypt": "^5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
"@types/jsonwebtoken": "^8.5.9",
|
|
||||||
"@types/marked": "^4.0.7",
|
|
||||||
"@types/node": "17.0.23",
|
"@types/node": "17.0.23",
|
||||||
"@types/react": "18.0.9",
|
"@types/react": "18.0.9",
|
||||||
"@types/react-datepicker": "4.4.1",
|
"@types/react-datepicker": "4.4.1",
|
||||||
"@types/react-dom": "18.0.3",
|
"@types/react-dom": "18.0.3",
|
||||||
"@types/showdown": "^2.0.0",
|
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint": "8.27.0",
|
"eslint": "8.27.0",
|
||||||
"eslint-config-next": "13.0.2",
|
"eslint-config-next": "13.0.2",
|
||||||
|
|
|
@ -1,55 +1,17 @@
|
||||||
// user.get("/self", jwt, async (req: UserJwtRequest, res, next) => {
|
import { getCurrentUser } from "@lib/server/session"
|
||||||
// const error = () =>
|
|
||||||
// res.status(401).json({
|
|
||||||
// message: "Unauthorized"
|
|
||||||
// })
|
|
||||||
|
|
||||||
import { USER_COOKIE_NAME } from "@lib/constants"
|
|
||||||
import { getUserById } from "@lib/server/prisma"
|
|
||||||
import { getCookie } from "cookies-next"
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
// try {
|
|
||||||
// if (!req.user) {
|
|
||||||
// return error()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const user = await User.findByPk(req.user?.id, {
|
|
||||||
// attributes: {
|
|
||||||
// exclude: ["password"]
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// if (!user) {
|
|
||||||
// return error()
|
|
||||||
// }
|
|
||||||
// res.json(user)
|
|
||||||
// } catch (error) {
|
|
||||||
// next(error)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
_: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const error = () =>
|
const error = () =>
|
||||||
res.status(401).json({
|
res.status(401).json({
|
||||||
message: "Unauthorized"
|
message: "Unauthorized"
|
||||||
})
|
})
|
||||||
|
|
||||||
const userId = String(
|
|
||||||
getCookie(USER_COOKIE_NAME, {
|
|
||||||
req,
|
|
||||||
res
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return error()
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await getUserById(userId)
|
const user = await getCurrentUser()
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return error()
|
return error()
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"next": "^13.0.3",
|
|
||||||
"eslint-config-next": "^13.0.3"
|
|
||||||
}
|
|
||||||
}
|
|
1321
pnpm-lock.yaml
1321
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
||||||
import * as dotenv from "dotenv"
|
|
||||||
dotenv.config()
|
|
||||||
|
|
||||||
import "./src/server"
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
|
||||||
"github": {
|
|
||||||
"silent": true,
|
|
||||||
"autoJobCancelation": true
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue