diff --git a/.env.example b/.env.example index 8a3c233..223b076 100644 --- a/.env.example +++ b/.env.example @@ -11,12 +11,6 @@ GITHUB_ACCESS_TOKEN="" DATABASE_URL="postgresql://postgres:postgres@localhost:54322/postgres?schema=nextjs-starter" -# Email -SMTP_FROM="" -POSTMARK_API_TOKEN="" -POSTMARK_SIGN_IN_TEMPLATE="" -POSTMARK_ACTIVATION_TEMPLATE="" - # Subscriptions (Stripe) STRIPE_API_KEY="" STRIPE_WEBHOOK_SECRET="" diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 45b2254..ce5e8cf 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -1,16 +1,16 @@ -import { Metadata } from "next" -import Link from "next/link" +import { Metadata } from "next"; +import Link from "next/link"; -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { LoginForm } from "@/components/auth/login-form" -import { Icons } from "@/components/icons" -import { UserAuthForm } from "@/components/user-auth-form" +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; +import { LoginForm } from "@/components/auth/login-form"; +import { Icons } from "@/components/icons"; +import { UserAuthForm } from "@/components/user-auth-form"; export const metadata: Metadata = { title: "Login", description: "Login to your account", -} +}; export default function LoginPage() { return ( @@ -37,8 +37,8 @@ export default function LoginPage() { Enter your email to sign in to your account

- +

- ) + ); } diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx index dca7ee4..00416b4 100644 --- a/app/(auth)/register/page.tsx +++ b/app/(auth)/register/page.tsx @@ -1,15 +1,15 @@ -import Link from "next/link" +import Link from "next/link"; -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { RegisterForm } from "@/components/auth/register-form" -import { Icons } from "@/components/icons" -import { UserAuthForm } from "@/components/user-auth-form" +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; +import { RegisterForm } from "@/components/auth/register-form"; +import { Icons } from "@/components/icons"; +import { UserAuthForm } from "@/components/user-auth-form"; export const metadata = { title: "Create an account", description: "Create an account to get started.", -} +}; export default async function RegisterPage() { return ( @@ -35,8 +35,8 @@ export default async function RegisterPage() { Enter your email below to create your account

- +

By clicking continue, you agree to our{" "} - ) + ); } diff --git a/app/(dashboard)/dashboard/billing/page.tsx b/app/(dashboard)/dashboard/billing/page.tsx index 0a601e5..10c738d 100644 --- a/app/(dashboard)/dashboard/billing/page.tsx +++ b/app/(dashboard)/dashboard/billing/page.tsx @@ -1,43 +1,42 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { stripe } from "@/lib/stripe" -import { getUserSubscriptionPlan } from "@/lib/subscription" -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" +import { redirect } from "next/navigation"; +import { authOptions } from "@/lib/auth.config"; +import { currentUser } from "@/lib/session"; +import { stripe } from "@/lib/stripe"; +import { getUserSubscriptionPlan } from "@/lib/subscription"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card" -import { BillingForm } from "@/components/billing-form" -import { DashboardHeader } from "@/components/header" -import { Icons } from "@/components/icons" -import { DashboardShell } from "@/components/shell" +} from "@/components/ui/card"; +import { BillingForm } from "@/components/billing-form"; +import { DashboardHeader } from "@/components/header"; +import { Icons } from "@/components/icons"; +import { DashboardShell } from "@/components/shell"; export const metadata = { title: "Billing", description: "Manage billing and your subscription plan.", -} +}; export default async function BillingPage() { - const user = await getCurrentUser() + const user = await currentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } - const subscriptionPlan = await getUserSubscriptionPlan(user.id) + const subscriptionPlan = await getUserSubscriptionPlan(user.id); // If user has a pro plan, check cancel status on Stripe. - let isCanceled = false + let isCanceled = false; if (subscriptionPlan.isPro && subscriptionPlan.stripeSubscriptionId) { const stripePlan = await stripe.subscriptions.retrieve( subscriptionPlan.stripeSubscriptionId - ) - isCanceled = stripePlan.cancel_at_period_end + ); + isCanceled = stripePlan.cancel_at_period_end; } return ( @@ -72,5 +71,5 @@ export default async function BillingPage() { /> - ) + ); } diff --git a/app/(dashboard)/dashboard/layout.tsx b/app/(dashboard)/dashboard/layout.tsx index 71a90d6..1fa1e88 100644 --- a/app/(dashboard)/dashboard/layout.tsx +++ b/app/(dashboard)/dashboard/layout.tsx @@ -1,23 +1,23 @@ -import { notFound } from "next/navigation" +import { notFound } from "next/navigation"; -import { dashboardConfig } from "@/config/dashboard" -import { getCurrentUser } from "@/lib/session" -import { MainNav } from "@/components/main-nav" -import { DashboardNav } from "@/components/nav" -import { SiteFooter } from "@/components/site-footer" -import { UserAccountNav } from "@/components/user-account-nav" +import { dashboardConfig } from "@/config/dashboard"; +import { currentUser } from "@/lib/session"; +import { MainNav } from "@/components/main-nav"; +import { DashboardNav } from "@/components/nav"; +import { SiteFooter } from "@/components/site-footer"; +import { UserAccountNav } from "@/components/user-account-nav"; interface DashboardLayoutProps { - children?: React.ReactNode + children?: React.ReactNode; } export default async function DashboardLayout({ children, }: DashboardLayoutProps) { - const user = await getCurrentUser() + const user = await currentUser(); if (!user) { - return notFound() + return notFound(); } return ( @@ -44,5 +44,5 @@ export default async function DashboardLayout({ - ) + ); } diff --git a/app/(dashboard)/dashboard/settings/page.tsx b/app/(dashboard)/dashboard/settings/page.tsx index e6e16e0..0497b8c 100644 --- a/app/(dashboard)/dashboard/settings/page.tsx +++ b/app/(dashboard)/dashboard/settings/page.tsx @@ -1,22 +1,21 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" -import { UserNameForm } from "@/components/user-name-form" +import { currentUser } from "@/lib/session"; +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { UserNameForm } from "@/components/user-name-form"; export const metadata = { title: "Settings", description: "Manage account and website settings.", -} +}; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await currentUser(); + + console.log("~~settings user ~~", user); - if (!user) { - redirect(authOptions?.pages?.signIn || "/login") - } + // if (!user) { + // redirect(authOptions?.pages?.signIn || "/login") + // } return ( @@ -25,8 +24,8 @@ export default async function SettingsPage() { text="Manage account and website settings." />

- + {/* */}
- ) + ); } diff --git a/app/(marketing)/blog/[...slug]/page.tsx b/app/(marketing)/blog/[...slug]/page.tsx index 6889a58..9386b48 100644 --- a/app/(marketing)/blog/[...slug]/page.tsx +++ b/app/(marketing)/blog/[...slug]/page.tsx @@ -1,50 +1,47 @@ -import { notFound } from "next/navigation" -import { allAuthors, allPosts } from "contentlayer/generated" - -import { Mdx } from "@/components/mdx-components" - -import "@/styles/mdx.css" -import { Metadata } from "next" -import Image from "next/image" -import Link from "next/link" - -import { env } from "@/env.mjs" -import { absoluteUrl, cn, formatDate } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { Icons } from "@/components/icons" +import { notFound } from "next/navigation"; +import { allAuthors, allPosts } from "contentlayer/generated"; +import { Mdx } from "@/components/mdx-components"; +import "@/styles/mdx.css"; +import { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; +import { env } from "@/env.mjs"; +import { absoluteUrl, cn, formatDate } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; +import { Icons } from "@/components/icons"; interface PostPageProps { params: { - slug: string[] - } + slug: string[]; + }; } async function getPostFromParams(params) { - const slug = params?.slug?.join("/") - const post = allPosts.find((post) => post.slugAsParams === slug) + const slug = params?.slug?.join("/"); + const post = allPosts.find((post) => post.slugAsParams === slug); if (!post) { - null + null; } - return post + return post; } export async function generateMetadata({ params, }: PostPageProps): Promise { - const post = await getPostFromParams(params) + const post = await getPostFromParams(params); if (!post) { - return {} + return {}; } - const url = env.NEXT_PUBLIC_APP_URL + const url = env.NEXT_PUBLIC_APP_URL; - const ogUrl = new URL(`${url}/api/og`) - ogUrl.searchParams.set("heading", post.title) - ogUrl.searchParams.set("type", "Blog Post") - ogUrl.searchParams.set("mode", "dark") + const ogUrl = new URL(`${url}/api/og`); + ogUrl.searchParams.set("heading", post.title); + ogUrl.searchParams.set("type", "Blog Post"); + ogUrl.searchParams.set("mode", "dark"); return { title: post.title, @@ -72,7 +69,7 @@ export async function generateMetadata({ description: post.description, images: [ogUrl.toString()], }, - } + }; } export async function generateStaticParams(): Promise< @@ -80,19 +77,19 @@ export async function generateStaticParams(): Promise< > { return allPosts.map((post) => ({ slug: post.slugAsParams.split("/"), - })) + })); } export default async function PostPage({ params }: PostPageProps) { - const post = await getPostFromParams(params) + const post = await getPostFromParams(params); if (!post) { - notFound() + notFound(); } const authors = post.authors.map((author) => allAuthors.find(({ slug }) => slug === `/authors/${author}`) - ) + ); return (
@@ -165,5 +162,5 @@ export default async function PostPage({ params }: PostPageProps) {
- ) + ); } diff --git a/components/auth/login-form.tsx b/components/auth/login-form.tsx index e78dfce..cf6e36b 100644 --- a/components/auth/login-form.tsx +++ b/components/auth/login-form.tsx @@ -1,11 +1,10 @@ "use client"; -import { startTransition, useState } from "react"; -import { useRouter } from "next/navigation"; +import { useState, useTransition } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import type * as z from "zod"; - import { login } from "@/lib/actions/auth"; import { loginSchema } from "@/lib/validations/auth"; import { Button } from "@/components/ui/button"; @@ -17,10 +16,12 @@ import { FormLabel, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import ErrorMessage from "../message/error-message"; const LoginForm = () => { - const router = useRouter(); - const [success, setSuccess] = useState(""); + const searchParams = useSearchParams(); + const callbackUrl = searchParams.get("callbackUrl"); + const [isPending, startTransition] = useTransition(); const [error, setError] = useState(""); const form = useForm>({ resolver: zodResolver(loginSchema), @@ -31,11 +32,17 @@ const LoginForm = () => { }); const handleSubmit = async (values: z.infer) => { - try { - login(values); - } catch (error) { - console.error(error); - } + startTransition(() => { + login(values, callbackUrl) + .then((data) => { + if (data?.error) { + setError(data.error); + } + }) + .catch(() => { + setError("Something went wrong"); + }); + }); }; return ( @@ -51,6 +58,7 @@ const LoginForm = () => { @@ -67,6 +75,7 @@ const LoginForm = () => { @@ -74,9 +83,13 @@ const LoginForm = () => { )} /> -
{success || error}
- + +
+
+
diff --git a/components/auth/register-form.tsx b/components/auth/register-form.tsx index bb341a6..10e8895 100644 --- a/components/auth/register-form.tsx +++ b/components/auth/register-form.tsx @@ -1,25 +1,27 @@ -"use client" +"use client"; -import { useState } from "react" -import { zodResolver } from "@hookform/resolvers/zod" -import { useForm } from "react-hook-form" -import type * as z from "zod" - -import { register } from "@/lib/actions/auth" -import { registerSchema } from "@/lib/validations/auth" -import { Button } from "@/components/ui/button" +import { useState, useTransition } from "react"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import type * as z from "zod"; +import { register } from "@/lib/actions/auth"; +import { registerSchema } from "@/lib/validations/auth"; +import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, -} from "@/components/ui/form" -import { Input } from "@/components/ui/input" +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import ErrorMessage from "../message/error-message"; +import SuccessMessage from "../message/success-message"; const RegisterForm = () => { - const [success, setSuccess] = useState("") - const [error, setError] = useState("") + const [isPending, startTransition] = useTransition(); + const [success, setSuccess] = useState(""); + const [error, setError] = useState(""); const form = useForm>({ resolver: zodResolver(registerSchema), defaultValues: { @@ -27,15 +29,20 @@ const RegisterForm = () => { email: "", password: "", }, - }) + }); const handleSubmit = async (values: z.infer) => { try { - register(values) + startTransition(() => { + register(values).then((data) => { + setSuccess(data?.success); + setError(data?.error); + }); + }); } catch (error) { - console.log() + setError("Something went wrong"); } - } + }; return (
@@ -48,7 +55,11 @@ const RegisterForm = () => { Name - + )} @@ -64,6 +75,7 @@ const RegisterForm = () => { {...field} placeholder="example@gmail.com" type="email" + disabled={isPending} /> @@ -80,19 +92,27 @@ const RegisterForm = () => { {...field} placeholder="Your password" type="password" + disabled={isPending} /> )} /> -
{success || error}
- + +
+
+ +
+
+
- ) -} + ); +}; -export { RegisterForm } +export { RegisterForm }; diff --git a/components/mdx-components.tsx b/components/mdx-components.tsx index dc0eab8..b5c79a0 100644 --- a/components/mdx-components.tsx +++ b/components/mdx-components.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import Image from "next/image"; - -// import { useMDXComponent } from "next-contentlayer/hooks" +import { useMDXComponent } from "next-contentlayer/hooks"; import { cn } from "@/lib/utils"; import { Callout } from "@/components/callout"; @@ -148,7 +147,8 @@ const components = { {...props} /> ), - Image, + // eslint-disable-next-line jsx-a11y/alt-text + Image: (props) => , Callout, Card: MdxCard, }; @@ -158,9 +158,11 @@ interface MdxProps { } export function Mdx({ code }: MdxProps) { - // const Component = useMDXComponent(code); + const Component = useMDXComponent(code); return ( -
{/* */}
+
+ {" "} +
); } diff --git a/components/message/error-message.tsx b/components/message/error-message.tsx new file mode 100644 index 0000000..76fd1f3 --- /dev/null +++ b/components/message/error-message.tsx @@ -0,0 +1,17 @@ +import { Alert, AlertDescription } from "@/components/ui/alert"; + +type ErrorMessageProps = { + message?: string; +}; + +const ErrorMessage = ({ message }: ErrorMessageProps) => { + if (!message) return null; + + return ( + + {message} + + ); +}; + +export default ErrorMessage; diff --git a/components/message/success-message.tsx b/components/message/success-message.tsx new file mode 100644 index 0000000..464c248 --- /dev/null +++ b/components/message/success-message.tsx @@ -0,0 +1,17 @@ +import { Alert, AlertDescription } from "@/components/ui/alert"; + +type SuccessMessageProps = { + message?: string; +}; + +const SuccessMessage = ({ message }: SuccessMessageProps) => { + if (!message) return null; + + return ( + + {message} + + ); +}; + +export default SuccessMessage; diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx index 6cd63fb..35428d4 100644 --- a/components/ui/alert.tsx +++ b/components/ui/alert.tsx @@ -1,7 +1,7 @@ -import * as React from "react" -import { VariantProps, cva } from "class-variance-authority" +import * as React from "react"; +import { VariantProps, cva } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const alertVariants = cva( "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11", @@ -11,13 +11,14 @@ const alertVariants = cva( default: "bg-background text-foreground", destructive: "text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive", + success: "text-green-500 border-green-500/50", }, }, defaultVariants: { variant: "default", }, } -) +); const Alert = React.forwardRef< HTMLDivElement, @@ -29,8 +30,8 @@ const Alert = React.forwardRef< className={cn(alertVariants({ variant }), className)} {...props} /> -)) -Alert.displayName = "Alert" +)); +Alert.displayName = "Alert"; const AlertTitle = React.forwardRef< HTMLParagraphElement, @@ -41,8 +42,8 @@ const AlertTitle = React.forwardRef< className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props} /> -)) -AlertTitle.displayName = "AlertTitle" +)); +AlertTitle.displayName = "AlertTitle"; const AlertDescription = React.forwardRef< HTMLParagraphElement, @@ -53,7 +54,7 @@ const AlertDescription = React.forwardRef< className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} /> -)) -AlertDescription.displayName = "AlertDescription" +)); +AlertDescription.displayName = "AlertDescription"; -export { Alert, AlertTitle, AlertDescription } +export { Alert, AlertTitle, AlertDescription }; diff --git a/components/user-auth-form.tsx b/components/user-auth-form.tsx index af745b3..f1ca4e5 100644 --- a/components/user-auth-form.tsx +++ b/components/user-auth-form.tsx @@ -1,23 +1,22 @@ -"use client" - -import * as React from "react" -import { useSearchParams } from "next/navigation" -import { zodResolver } from "@hookform/resolvers/zod" -import { signIn } from "next-auth/react" -import { useForm } from "react-hook-form" -import * as z from "zod" - -import { cn } from "@/lib/utils" -import { userAuthSchema } from "@/lib/validations/auth" -import { buttonVariants } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import { toast } from "@/components/ui/use-toast" -import { Icons } from "@/components/icons" +"use client"; + +import * as React from "react"; +import { useSearchParams } from "next/navigation"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { signIn } from "next-auth/react"; +import { useForm } from "react-hook-form"; +import * as z from "zod"; +import { cn } from "@/lib/utils"; +import { userAuthSchema } from "@/lib/validations/auth"; +import { buttonVariants } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { toast } from "@/components/ui/use-toast"; +import { Icons } from "@/components/icons"; interface UserAuthFormProps extends React.HTMLAttributes {} -type FormData = z.infer +type FormData = z.infer; export function UserAuthForm({ className, ...props }: UserAuthFormProps) { const { @@ -26,68 +25,11 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { formState: { errors }, } = useForm({ resolver: zodResolver(userAuthSchema), - }) - const [isLoading, setIsLoading] = React.useState(false) - const [isGitHubLoading, setIsGitHubLoading] = React.useState(false) - const searchParams = useSearchParams() - - async function onSubmit(data: FormData) { - setIsLoading(true) - - const signInResult = await signIn("email", { - email: data.email.toLowerCase(), - redirect: false, - callbackUrl: searchParams?.get("from") || "/dashboard", - }) - - setIsLoading(false) - - if (!signInResult?.ok) { - return toast({ - title: "Something went wrong.", - description: "Your sign in request failed. Please try again.", - variant: "destructive", - }) - } - - return toast({ - title: "Check your email", - description: "We sent you a login link. Be sure to check your spam too.", - }) - } + }); + const [isGitHubLoading, setIsGitHubLoading] = React.useState(false); return (
-
-
-
- - - {errors?.email && ( -

- {errors.email.message} -

- )} -
- -
-
@@ -102,10 +44,10 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { type="button" className={cn(buttonVariants({ variant: "outline" }))} onClick={() => { - setIsGitHubLoading(true) - signIn("github") + setIsGitHubLoading(true); + signIn("github"); }} - disabled={isLoading || isGitHubLoading} + disabled={isGitHubLoading} > {isGitHubLoading ? ( @@ -115,5 +57,5 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { Github
- ) + ); } diff --git a/env.mjs b/env.mjs index b3e960a..e11d0c9 100644 --- a/env.mjs +++ b/env.mjs @@ -1,5 +1,5 @@ -import { createEnv } from "@t3-oss/env-nextjs" -import { z } from "zod" +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; export const env = createEnv({ server: { @@ -11,10 +11,6 @@ export const env = createEnv({ GITHUB_CLIENT_SECRET: z.string().min(1), GITHUB_ACCESS_TOKEN: z.string().min(1), DATABASE_URL: z.string().min(1), - SMTP_FROM: z.string().min(1), - POSTMARK_API_TOKEN: z.string().min(1), - POSTMARK_SIGN_IN_TEMPLATE: z.string().min(1), - POSTMARK_ACTIVATION_TEMPLATE: z.string().min(1), STRIPE_API_KEY: z.string().min(1), STRIPE_WEBHOOK_SECRET: z.string().min(1), STRIPE_PRO_MONTHLY_PLAN_ID: z.string().min(1), @@ -29,13 +25,9 @@ export const env = createEnv({ GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET, GITHUB_ACCESS_TOKEN: process.env.GITHUB_ACCESS_TOKEN, DATABASE_URL: process.env.DATABASE_URL, - SMTP_FROM: process.env.SMTP_FROM, - POSTMARK_API_TOKEN: process.env.POSTMARK_API_TOKEN, - POSTMARK_SIGN_IN_TEMPLATE: process.env.POSTMARK_SIGN_IN_TEMPLATE, - POSTMARK_ACTIVATION_TEMPLATE: process.env.POSTMARK_ACTIVATION_TEMPLATE, STRIPE_API_KEY: process.env.STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET, STRIPE_PRO_MONTHLY_PLAN_ID: process.env.STRIPE_PRO_MONTHLY_PLAN_ID, NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL, }, -}) +}); diff --git a/lib/actions/auth.ts b/lib/actions/auth.ts index bd553a0..682ad0b 100644 --- a/lib/actions/auth.ts +++ b/lib/actions/auth.ts @@ -1,6 +1,7 @@ "use server"; import { isRedirectError } from "next/dist/client/components/redirect"; +import { DEFAULT_LOGIN_REDIRECT } from "@/routes"; import bcryptjs from "bcryptjs"; import { AuthError } from "next-auth"; import type * as z from "zod"; @@ -40,7 +41,10 @@ export async function register(values: z.infer) { return { success: "Account creation succeeded" }; } -export async function login(values: z.infer) { +export async function login( + values: z.infer, + callbackUrl?: string | null +) { const validatedFields = loginSchema.safeParse(values); if (!validatedFields.success) { @@ -62,7 +66,7 @@ export async function login(values: z.infer) { await signIn("credentials", { email, password, - redirectTo: "/", + redirectTo: callbackUrl || DEFAULT_LOGIN_REDIRECT, }); } catch (error) { if (error instanceof AuthError) { diff --git a/lib/auth.config.ts b/lib/auth.config.ts index b7a9a46..e7e3407 100644 --- a/lib/auth.config.ts +++ b/lib/auth.config.ts @@ -1,18 +1,11 @@ import bcrypt from "bcryptjs"; -import NextAuth, { type NextAuthConfig } from "next-auth"; +import { type NextAuthConfig } from "next-auth"; import Credentials from "next-auth/providers/credentials"; -import EmailProvider from "next-auth/providers/email"; import GitHubProvider from "next-auth/providers/github"; -import { Client } from "postmark"; - import { env } from "@/env.mjs"; -import { siteConfig } from "@/config/site"; - import { db } from "./db"; import { loginSchema } from "./validations/auth"; -const postmarkClient = new Client(env.POSTMARK_API_TOKEN); - export const authOptions: NextAuthConfig = { providers: [ GitHubProvider({ diff --git a/lib/auth.ts b/lib/auth.ts index 1641543..6c442f6 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,9 +1,6 @@ import { PrismaAdapter } from "@auth/prisma-adapter"; -import NextAuth, { type NextAuthConfig } from "next-auth"; - -import { env } from "@/env.mjs"; +import NextAuth from "next-auth"; import { db } from "@/lib/db"; - import { authOptions } from "./auth.config"; export const { @@ -25,10 +22,10 @@ export const { id: user.id, }, }); + // TODO add email verification if (!existingUser) return false; - console.log("~~signIn 返回~~", true); return true; }, async session({ token, session }) { @@ -40,7 +37,6 @@ export const { session.user.email = token.email; } - console.log("~~session 返回~~", session); return session; }, async jwt({ token, user }) { @@ -61,7 +57,6 @@ export const { token.name = existingUser.name; token.email = existingUser.email; - console.log("~~jwt 返回~~", token); return token; }, }, diff --git a/lib/session.ts b/lib/session.ts index d570582..68c71f8 100644 --- a/lib/session.ts +++ b/lib/session.ts @@ -1,9 +1,7 @@ -import { getServerSession } from "next-auth/next" +import { auth } from "./auth"; -import { authOptions } from "@/lib/auth" +export async function currentUser() { + const session = await auth(); -export async function getCurrentUser() { - const session = await getServerSession(authOptions) - - return session?.user + return session?.user; } diff --git a/middleware.ts b/middleware.ts index d876479..1f8c599 100644 --- a/middleware.ts +++ b/middleware.ts @@ -11,6 +11,7 @@ import { authOptions } from "./lib/auth.config"; const { auth } = NextAuth(authOptions); export default auth((req) => { + console.log("~~auth~~", req.auth); const { nextUrl } = req; const isLoggedIn = !!req.auth; diff --git a/middlewares.ts b/middlewares.ts deleted file mode 100644 index ab4927a..0000000 --- a/middlewares.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NextResponse } from "next/server" -import { getToken } from "next-auth/jwt" -import { withAuth } from "next-auth/middleware" - -export default withAuth( - async function middleware(req) { - const token = await getToken({ req }) - const isAuth = !!token - const isAuthPage = - req.nextUrl.pathname.startsWith("/login") || - req.nextUrl.pathname.startsWith("/register") - - if (isAuthPage) { - if (isAuth) { - return NextResponse.redirect(new URL("/dashboard", req.url)) - } - - return null - } - - if (!isAuth) { - let from = req.nextUrl.pathname - if (req.nextUrl.search) { - from += req.nextUrl.search - } - - return NextResponse.redirect( - new URL(`/login?from=${encodeURIComponent(from)}`, req.url) - ) - } - }, - { - callbacks: { - async authorized() { - // This is a work-around for handling redirect on auth pages. - // We return true here so that the middleware function above - // is always called. - return true - }, - }, - } -) - -export const config = { - matcher: ["/dashboard/:path*", "/editor/:path*", "/login", "/register"], -} diff --git a/package.json b/package.json index 286ce9d..34e7ccc 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "lucide-react": "^0.92.0", "next": "14.0.4", "next-auth": "^5.0.0-beta.4", + "next-contentlayer": "^0.3.4", "next-themes": "^0.2.1", "nodemailer": "^6.9.1", "postmark": "^3.0.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 873911f..da88fb4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -176,6 +176,9 @@ dependencies: next-auth: specifier: ^5.0.0-beta.4 version: 5.0.0-beta.4(next@14.0.4)(nodemailer@6.9.1)(react@18.2.0) + next-contentlayer: + specifier: ^0.3.4 + version: 0.3.4(contentlayer@0.3.1)(esbuild@0.17.18)(next@14.0.4)(react-dom@18.2.0)(react@18.2.0) next-themes: specifier: ^0.2.1 version: 0.2.1(next@14.0.4)(react-dom@18.2.0)(react@18.2.0) @@ -793,6 +796,35 @@ packages: - supports-color dev: false + /@contentlayer/core@0.3.4(esbuild@0.17.18): + resolution: {integrity: sha512-o68oBLwfYZ+2vtgfk1lgHxOl3LoxvRNiUfeQ8IWFWy/L4wnIkKIqLZX01zlRE5IzYM+ZMMN5V0cKQlO7DsyR9g==} + peerDependencies: + esbuild: 0.17.x || 0.18.x + markdown-wasm: 1.x + peerDependenciesMeta: + esbuild: + optional: true + markdown-wasm: + optional: true + dependencies: + '@contentlayer/utils': 0.3.4 + camel-case: 4.1.2 + comment-json: 4.2.3 + esbuild: 0.17.18 + gray-matter: 4.0.3 + mdx-bundler: 9.2.1(esbuild@0.17.18) + rehype-stringify: 9.0.3 + remark-frontmatter: 4.0.1 + remark-parse: 10.0.2 + remark-rehype: 10.1.0 + source-map-support: 0.5.21 + type-fest: 3.13.1 + unified: 10.1.2 + transitivePeerDependencies: + - '@effect-ts/otel-node' + - supports-color + dev: false + /@contentlayer/source-files@0.3.1(esbuild@0.17.18): resolution: {integrity: sha512-XXBW3cm1flykXw0WKUojSRGDGpQ7gCa5VWNQom9qSI7OE5j5WYua2dkzhQhblf3WKLvVUDF5vRBwoc+6aIB6ew==} dependencies: @@ -860,6 +892,39 @@ packages: type-fest: 3.8.0 dev: false + /@contentlayer/utils@0.3.4: + resolution: {integrity: sha512-ZWWOhbUWYQ2QHoLIlcUnEo7X4ZbwcyFPuzVQWWMkK43BxCveyQtZwBIzfyx54sqVzi0GUmKP8bHzsLQT0QxaLQ==} + peerDependencies: + '@effect-ts/otel-node': '*' + peerDependenciesMeta: + '@effect-ts/core': + optional: true + '@effect-ts/otel': + optional: true + '@effect-ts/otel-node': + optional: true + dependencies: + '@effect-ts/core': 0.60.5 + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0) + '@effect-ts/otel-exporter-trace-otlp-grpc': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/exporter-trace-otlp-grpc@0.39.1)(@opentelemetry/sdk-trace-base@1.19.0) + '@effect-ts/otel-sdk-trace-node': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0)(@opentelemetry/sdk-trace-node@1.19.0) + '@js-temporal/polyfill': 0.4.4 + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.39.1(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-node': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 + chokidar: 3.5.3 + hash-wasm: 4.9.0 + inflection: 2.0.1 + memfs: 3.5.1 + oo-ascii-tree: 1.93.0 + ts-pattern: 4.3.0 + type-fest: 3.13.1 + dev: false + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -946,6 +1011,23 @@ packages: '@opentelemetry/sdk-trace-base': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@effect-ts/otel-exporter-trace-otlp-grpc@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/exporter-trace-otlp-grpc@0.39.1)(@opentelemetry/sdk-trace-base@1.19.0): + resolution: {integrity: sha512-47gAg0O2pW5Jlo86jfzjdkwL5a7Bzb+Kj5WTmdu4CxYRfWn9ytKjuuYIfsNDW8neuhdKzn+P5wCddgEh0glYyQ==} + peerDependencies: + '@effect-ts/core': ^0.60.2 + '@opentelemetry/api': ^1.4.0 + '@opentelemetry/core': ^1.13.0 + '@opentelemetry/exporter-trace-otlp-grpc': ^0.39.0 + '@opentelemetry/sdk-trace-base': ^1.13.0 + dependencies: + '@effect-ts/core': 0.60.5 + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0) + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/exporter-trace-otlp-grpc': 0.39.1(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) + dev: false + /@effect-ts/otel-sdk-trace-node@0.14.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.1.0)(@opentelemetry/core@1.5.0)(@opentelemetry/sdk-trace-base@1.5.0)(@opentelemetry/sdk-trace-node@1.5.0): resolution: {integrity: sha512-j5ynRvd0H+Fp9aH/5NOtBd1ogNMpNB3r7uiXOKRPlfKUOtdx4KsCt2cPBjChMvyLstj8dkjtWE4loLSTYkWPuA==} peerDependencies: @@ -963,6 +1045,23 @@ packages: '@opentelemetry/sdk-trace-node': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@effect-ts/otel-sdk-trace-node@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0)(@opentelemetry/sdk-trace-node@1.19.0): + resolution: {integrity: sha512-a2sF0ylmn8xOJs8fNeT/spJ1gUcsksAJCALxo9WOfuTCMtTwMVtVhCKEPEeQoL7wFqU+JgPkVdP91+FJ/Rkeow==} + peerDependencies: + '@effect-ts/core': ^0.60.2 + '@opentelemetry/api': ^1.4.0 + '@opentelemetry/core': ^1.13.0 + '@opentelemetry/sdk-trace-base': ^1.13.0 + '@opentelemetry/sdk-trace-node': ^1.13.0 + dependencies: + '@effect-ts/core': 0.60.5 + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0) + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-node': 1.19.0(@opentelemetry/api@1.7.0) + dev: false + /@effect-ts/otel@0.14.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.1.0)(@opentelemetry/core@1.5.0)(@opentelemetry/sdk-trace-base@1.5.0): resolution: {integrity: sha512-WtkxdoM1M8bl7F1mrSwBZQJAIaUXcupePrllL7iZnvSfUVhYXV98gRTV6EiVT+prX7rzCW4wPkF/XsyWbtMDtA==} peerDependencies: @@ -977,6 +1076,20 @@ packages: '@opentelemetry/sdk-trace-base': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@effect-ts/otel@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.7.0)(@opentelemetry/core@1.19.0)(@opentelemetry/sdk-trace-base@1.19.0): + resolution: {integrity: sha512-AmZJHl7t0+Peh7Yb2+hqn6r9+rd9/UfeA4AMV9h0YGTdOyouyFfD3wzWlxnAUzAQ4Lrod4kC7Noruret4EpqpA==} + peerDependencies: + '@effect-ts/core': ^0.60.2 + '@opentelemetry/api': ^1.4.0 + '@opentelemetry/core': ^1.13.0 + '@opentelemetry/sdk-trace-base': ^1.13.0 + dependencies: + '@effect-ts/core': 0.60.5 + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) + dev: false + /@effect-ts/system@0.57.5: resolution: {integrity: sha512-/crHGujo0xnuHIYNc1VgP0HGJGFSoSqq88JFXe6FmFyXPpWt8Xu39LyLg7rchsxfXFeEdA9CrIZvLV5eswXV5g==} dev: false @@ -1379,6 +1492,14 @@ packages: tslib: 2.5.0 dev: false + /@js-temporal/polyfill@0.4.4: + resolution: {integrity: sha512-2X6bvghJ/JAoZO52lbgyAPFj8uCflhTo2g7nkFzEQdXd/D8rEeD4HtmTEpmtGCva260fcd66YNXBOYdnmHqSOg==} + engines: {node: '>=12'} + dependencies: + jsbi: 4.3.0 + tslib: 2.5.0 + dev: false + /@mapbox/node-pre-gyp@1.0.11: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true @@ -1423,7 +1544,7 @@ packages: markdown-extensions: 1.1.1 periscopic: 3.1.0 remark-mdx: 2.3.0 - remark-parse: 10.0.1 + remark-parse: 10.0.2 remark-rehype: 10.1.0 unified: 10.1.2 unist-util-position-from-estree: 1.1.2 @@ -1547,6 +1668,13 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@opentelemetry/api-logs@0.39.1: + resolution: {integrity: sha512-9BJ8lMcOzEN0lu+Qji801y707oFO4xT3db6cosPvl+k7ItUHKN5ofWqtSbM9gbt1H4JJ/4/2TVrqI9Rq7hNv6Q==} + engines: {node: '>=14'} + dependencies: + '@opentelemetry/api': 1.7.0 + dev: false + /@opentelemetry/api-metrics@0.31.0: resolution: {integrity: sha512-PcL1x0kZtMie7NsNy67OyMvzLEXqf3xd0TZJKHHPMGTe89oMpNVrD1zJB1kZcwXOxLlHHb6tz21G3vvXPdXyZg==} engines: {node: '>=14'} @@ -1560,6 +1688,20 @@ packages: engines: {node: '>=8.0.0'} dev: false + /@opentelemetry/api@1.7.0: + resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} + engines: {node: '>=8.0.0'} + dev: false + + /@opentelemetry/context-async-hooks@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-0i1ECOc9daKK3rjUgDDXf0GDD5XfCou5lXnt2DALIc2qKoruPPcesobNKE54laSVUWnC3jX26RzuOa31g0V32A==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + dev: false + /@opentelemetry/context-async-hooks@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-mhBPP0BU0RaH2HB8U4MDd5OjWA1y7SoLOovCT0iEpJAltaq2z04uxRJVzIs91vkpNnV0utUZowQQD3KElgU+VA==} engines: {node: '>=14'} @@ -1569,6 +1711,26 @@ packages: '@opentelemetry/api': 1.1.0 dev: false + /@opentelemetry/core@1.13.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-2dBX3Sj99H96uwJKvc2w9NOiNgbvAO6mOFJFramNkKfS9O4Um+VWgpnlAazoYjT6kUJ1MP70KQ5ngD4ed+4NUw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.5.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/semantic-conventions': 1.13.0 + dev: false + + /@opentelemetry/core@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-w42AukJh3TP8R0IZZOVJVM/kMWu8g+lm4LzT70WtuKqhwq7KVhcDzZZuZinWZa6TtQCl7Smt2wolEYzpHabOgw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/semantic-conventions': 1.19.0 + dev: false + /@opentelemetry/core@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-B3DIMkQN0DANrr7XrMLS4pR6d2o/jqT09x4nZJz6wSJ9SHr4eQIqeFBNeEUQG1I+AuOcH2UbJtgFm7fKxLqd+w==} engines: {node: '>=14'} @@ -1595,6 +1757,21 @@ packages: '@opentelemetry/sdk-trace-base': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/exporter-trace-otlp-grpc@0.39.1(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-l5RhLKx6U+yuLhMrtgavTDthX50E1mZM3/SSySC7OPZiArFHV/b/9x9jxAzrOgIQUDxyj4N0V9aLKSA2t7Qzxg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + dependencies: + '@grpc/grpc-js': 1.8.14 + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/otlp-grpc-exporter-base': 0.39.1(@opentelemetry/api@1.7.0) + '@opentelemetry/otlp-transformer': 0.39.1(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.13.0(@opentelemetry/api@1.7.0) + dev: false + /@opentelemetry/otlp-exporter-base@0.31.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-MI+LtGo/ZYL/g7ldWTAY9vMjMqlcWMj2undgcnq8Y5BoDLI8oBwGn//Lizjk4NikF+SkcolKB3+U05nCeT5djg==} engines: {node: '>=14'} @@ -1605,6 +1782,16 @@ packages: '@opentelemetry/core': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/otlp-exporter-base@0.39.1(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-Pv5X8fbi6jD/RJBePyn7MnCSuE6MbPB6dl+7YYBWJ5RcMGYMwvLXjd4h2jWsPV2TSUg38H/RoSP0aXvQ06Y7iw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + dev: false + /@opentelemetry/otlp-grpc-exporter-base@0.31.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-TfNZsQhWNd05CAaOwgN2lVthC8mkxvoArV6LfSyKyqSZ6srCnYPuW64yS/9buEhNvTkT3y63dzkVSnnv/1b3ow==} engines: {node: '>=14'} @@ -1618,6 +1805,19 @@ packages: '@opentelemetry/otlp-exporter-base': 0.31.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/otlp-grpc-exporter-base@0.39.1(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-u3ErFRQqQFKjjIMuwLWxz/tLPYInfmiAmSy//fGSCzCh2ZdJgqQjMOAxBgqFtCF2xFL+OmMhyuC2ThMzceGRWA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.0.0 + dependencies: + '@grpc/grpc-js': 1.8.14 + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/otlp-exporter-base': 0.39.1(@opentelemetry/api@1.7.0) + protobufjs: 7.2.3 + dev: false + /@opentelemetry/otlp-transformer@0.31.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-xCEsB0gTs7s/FMEv8+DWE6awfHJ5oHkFKSGePr6tT5Mh95rd1845WTefvLc++mYpewY8KnQ7tyo/zEfwywCIhw==} engines: {node: '>=14'} @@ -1632,6 +1832,31 @@ packages: '@opentelemetry/sdk-trace-base': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/otlp-transformer@0.39.1(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-0hgVnXXz5efI382B/24NxD4b6Zxlh7nxCdJkxkdmQMbn0yRiwoq/ZT+QG8eUL6JNzsBAV1WJlF5aJNsL8skHvw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.5.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/api-logs': 0.39.1 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-logs': 0.39.1(@opentelemetry/api-logs@0.39.1)(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-metrics': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.13.0(@opentelemetry/api@1.7.0) + dev: false + + /@opentelemetry/propagator-b3@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-v7y5IBOKBm0vP3yf0DHzlw4L2gL6tZ0KeeMTaxfO5IuomMffDbrGWcvYFp0Dt4LdZctTSK523rVLBB9FBHBciQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + dev: false + /@opentelemetry/propagator-b3@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-38iGIScgU9OLhoPKAV3p2rEf4RmmQC/Lo4LvpQ6TaSQrRht/oDgnpsPJnmNQLFboklmukKataJO+FhAieOc7mg==} engines: {node: '>=14'} @@ -1642,6 +1867,16 @@ packages: '@opentelemetry/core': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/propagator-jaeger@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-dedkOoTzKg+nYoLWCMp0Im+wo+XkTRW6aXhi8VQRtMW/9SNJGOllCJSu8llToLxMDF0+6zu7OCrKkevAof2tew==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + dev: false + /@opentelemetry/propagator-jaeger@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-aSUH5RDEZj+lmy4PbXAJ26E+yJcZloyPUBWgqYX+JBS4NnbriIznCF/tXV5s/RUXeVABibi/+yAZndv+2XBg4w==} engines: {node: '>=14'} @@ -1652,6 +1887,28 @@ packages: '@opentelemetry/core': 1.5.0(@opentelemetry/api@1.1.0) dev: false + /@opentelemetry/resources@1.13.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-euqjOkiN6xhjE//0vQYGvbStxoD/WWQRhDiO0OTLlnLBO9Yw2Gd/VoSx2H+svsebjzYk5OxLuREBmcdw6rbUNg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.5.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.13.0 + dev: false + + /@opentelemetry/resources@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-RgxvKuuMOf7nctOeOvpDjt2BpZvZGr9Y0vf7eGtY5XYZPkh2p7e2qub1S2IArdBMf9kEbz0SfycqCviOu9isqg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 + dev: false + /@opentelemetry/resources@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-YeEfC6IY54U3xL3P2+UAiom+r50ZF2jM0J47RV5uTFGF19Xjd5zazSwDPgmxtAd6DwLX0/5S5iqrsH4nEXMYoA==} engines: {node: '>=14'} @@ -1663,6 +1920,19 @@ packages: '@opentelemetry/semantic-conventions': 1.5.0 dev: false + /@opentelemetry/sdk-logs@0.39.1(@opentelemetry/api-logs@0.39.1)(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-/gmgKfZ1ZVFporKuwsewqIyvaUIGpv76JZ7lBpHQQPb37IMpaXO6pdqFI4ebHAWfNIm3akMyhmdtzivcgF3lgw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.5.0' + '@opentelemetry/api-logs': '>=0.38.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/api-logs': 0.39.1 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.13.0(@opentelemetry/api@1.7.0) + dev: false + /@opentelemetry/sdk-metrics-base@0.31.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-4R2Bjl3wlqIGcq4bCoI9/pD49ld+tEoM9n85UfFzr/aUe+2huY2jTPq/BP9SVB8d2Zfg7mGTIFeapcEvAdKK7g==} engines: {node: '>=14'} @@ -1677,6 +1947,42 @@ packages: lodash.merge: 4.6.2 dev: false + /@opentelemetry/sdk-metrics@1.13.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-MOjZX6AnSOqLliCcZUrb+DQKjAWXBiGeICGbHAGe5w0BB18PJIeIo995lO5JSaFfHpmUMgJButTPfJJD27W3Vg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.5.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.13.0(@opentelemetry/api@1.7.0) + lodash.merge: 4.6.2 + dev: false + + /@opentelemetry/sdk-trace-base@1.13.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-moTiQtc0uPR1hQLt6gLDJH9IIkeBhgRb71OKjNHZPE1VF45fHtD6nBDi5J/DkTHTwYP5X3kBJLa3xN7ub6J4eg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.5.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.13.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.13.0 + dev: false + + /@opentelemetry/sdk-trace-base@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-+IRvUm+huJn2KqfFW3yW/cjvRwJ8Q7FzYHoUNx5Fr0Lws0LxjMJG1uVB8HDpLwm7mg5XXH2M5MF+0jj5cM8BpQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/resources': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/semantic-conventions': 1.19.0 + dev: false + /@opentelemetry/sdk-trace-base@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-6lx7YDf67HSQYuWnvq3XgSrWikDJLiGCbrpUP6UWJ5Z47HLcJvwZPRH+cQGJu1DFS3dT2cV3GpAR75/OofPNHQ==} engines: {node: '>=14'} @@ -1689,6 +1995,21 @@ packages: '@opentelemetry/semantic-conventions': 1.5.0 dev: false + /@opentelemetry/sdk-trace-node@1.19.0(@opentelemetry/api@1.7.0): + resolution: {integrity: sha512-TCiEq/cUjM15RFqBRwWomTVbOqzndWL4ILa7ZCu0zbjU1/XY6AgHkgrgAc7vGP6TjRqH4Xryuglol8tcIfbBUQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.8.0' + dependencies: + '@opentelemetry/api': 1.7.0 + '@opentelemetry/context-async-hooks': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/core': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/propagator-b3': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/propagator-jaeger': 1.19.0(@opentelemetry/api@1.7.0) + '@opentelemetry/sdk-trace-base': 1.19.0(@opentelemetry/api@1.7.0) + semver: 7.5.4 + dev: false + /@opentelemetry/sdk-trace-node@1.5.0(@opentelemetry/api@1.1.0): resolution: {integrity: sha512-MzS+urf2KufpwgaHbGcUgccHr6paxI98lHFMgJAkK6w76AmPYavsxSwjiVPrchy/24d2J9svDirSgui3NNZo8g==} engines: {node: '>=14'} @@ -1704,6 +2025,16 @@ packages: semver: 7.5.0 dev: false + /@opentelemetry/semantic-conventions@1.13.0: + resolution: {integrity: sha512-LMGqfSZkaMQXqewO0o1wvWr/2fQdCh4a3Sqlxka/UsJCe0cfLulh6x2aqnKLnsrSGiCq5rSCwvINd152i0nCqw==} + engines: {node: '>=14'} + dev: false + + /@opentelemetry/semantic-conventions@1.19.0: + resolution: {integrity: sha512-14jRpC8f5c0gPSwoZ7SbEJni1PqI+AhAE8m1bMz6v+RPM4OlP1PT2UHBJj5Qh/ALLPjhVU/aZUK3YyjTUqqQVg==} + engines: {node: '>=14'} + dev: false + /@opentelemetry/semantic-conventions@1.5.0: resolution: {integrity: sha512-wlYG/U6ddW1ilXslnDLLQYJ8nd97W8JJTTfwkGhubx6dzW6SUkd+N4/MzTjjyZlrHQunxHtkHFvVpUKiROvFDw==} engines: {node: '>=14'} @@ -6257,6 +6588,27 @@ packages: react: 18.2.0 dev: false + /next-contentlayer@0.3.4(contentlayer@0.3.1)(esbuild@0.17.18)(next@14.0.4)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UtUCwgAl159KwfhNaOwyiI7Lg6sdioyKMeh+E7jxx0CJ29JuXGxBEYmCI6+72NxFGIFZKx8lvttbbQhbnYWYSw==} + peerDependencies: + contentlayer: 0.3.4 + next: ^12 || ^13 + react: '*' + react-dom: '*' + dependencies: + '@contentlayer/core': 0.3.4(esbuild@0.17.18) + '@contentlayer/utils': 0.3.4 + contentlayer: 0.3.1(esbuild@0.17.18) + next: 14.0.4(@babel/core@7.21.4)(@opentelemetry/api@1.1.0)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@effect-ts/otel-node' + - esbuild + - markdown-wasm + - supports-color + dev: false + /next-themes@0.2.1(next@14.0.4)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} peerDependencies: @@ -6503,6 +6855,11 @@ packages: engines: {node: '>= 14.6.0'} dev: false + /oo-ascii-tree@1.93.0: + resolution: {integrity: sha512-zbmrGCL/UsvxV2WlnsSrqdkdxEggxH7eA1HOk+hmimLQu+eLO4Y3VGqwt0VK04Nfe6iG6GnzRL5/XjH0j1v8bQ==} + engines: {node: '>= 14.17.0'} + dev: false + /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} @@ -7193,6 +7550,16 @@ packages: transitivePeerDependencies: - supports-color + /remark-parse@10.0.2: + resolution: {integrity: sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==} + dependencies: + '@types/mdast': 3.0.11 + mdast-util-from-markdown: 1.3.0 + unified: 10.1.2 + transitivePeerDependencies: + - supports-color + dev: false + /remark-rehype@10.1.0: resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==} dependencies: @@ -7357,6 +7724,14 @@ packages: dependencies: lru-cache: 6.0.0 + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: false @@ -7853,6 +8228,10 @@ packages: resolution: {integrity: sha512-qzJMo2pbkUJWusRH5o8xR+xogn6RmvViyUgwBFTtRENLse470clCGjHDf6haWGZ1AOmk8XkEohUoBW8Uut6Scg==} dev: false + /ts-pattern@4.3.0: + resolution: {integrity: sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==} + dev: false + /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} dependencies: @@ -7918,6 +8297,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: false + /type-fest@3.8.0: resolution: {integrity: sha512-FVNSzGQz9Th+/9R6Lvv7WIAkstylfHN2/JYxkyhhmKFYh9At2DST8t6L6Lref9eYO8PXFTfG9Sg1Agg0K3vq3Q==} engines: {node: '>=14.16'} diff --git a/prettier.config.js b/prettier.config.js index f39b41e..3247ef3 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -8,7 +8,6 @@ module.exports = { "^(react/(.*)$)|^(react$)", "^(next/(.*)$)|^(next$)", "", - "", "^types$", "^@/env(.*)$", "^@/types/(.*)$", @@ -19,7 +18,6 @@ module.exports = { "^@/components/(.*)$", "^@/styles/(.*)$", "^@/app/(.*)$", - "", "^[./]", ], importOrderSeparation: false, @@ -29,4 +27,4 @@ module.exports = { importOrderMergeDuplicateImports: true, importOrderCombineTypeAndValueImports: true, plugins: ["@ianvs/prettier-plugin-sort-imports"], -} +};