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 (
-
@@ -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"],
-}
+};