diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dc0218b --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +MONGO_URI= + +UPLOADTHING_SECRET= +UPLOADTHING_APP_ID= + +ADMIN_USERNAME= +ADMIN_PASSWORD= \ No newline at end of file diff --git a/app/(auth)/admin/downloads/page.tsx b/app/(auth)/admin/downloads/page.tsx index 0625f43..5d0b28f 100644 --- a/app/(auth)/admin/downloads/page.tsx +++ b/app/(auth)/admin/downloads/page.tsx @@ -1,70 +1,125 @@ "use client"; -import { downloadSchema } from "@/lib/validations/validation"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; +import React from "react"; +import { useForm, SubmitHandler } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; import { Button } from "@/components/ui/button"; import { Form, FormControl, - FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { UploadButton, UploadDropzone } from "@/lib/uploadthing"; +import { downloadSchema } from "@/lib/validations/validation"; -const DownloadPage = () => { +const AdminPage = () => { const form = useForm>({ resolver: zodResolver(downloadSchema), - defaultValues: { - username: "", - }, }); - function onSubmit(values: z.infer) { - // Do something with the form values. - // ✅ This will be type-safe and validated. - console.log(values); - } + const onSubmit: SubmitHandler> = async ( + data + ) => { + const response = await fetch("/api/upload", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); + + if (response.ok) { + console.log("Upload successful"); + alert("Uploaded"); + form.reset(); + } else { + console.error("Upload failed"); + alert("Upload Failed"); + } + }; return ( -
-

Download Section

- -
-
- +

Admin Upload Section

+ + + ( + + File Name + + + + + + )} + /> + ( + + Version + + + + + + )} + /> + ( + + Download Link + { + field.onChange(res[0].url); + }} + onUploadError={(error: Error) => { + alert(`ERROR! ${error.message}`); + }} + /> + + + + + + )} + /> + ( + + File Size + + + + + + )} + /> + - - -
+ Submit + + +
); }; -export default DownloadPage; +export default AdminPage; diff --git a/app/(root)/downloads/page.tsx b/app/(root)/downloads/page.tsx index 4f2662d..f256830 100644 --- a/app/(root)/downloads/page.tsx +++ b/app/(root)/downloads/page.tsx @@ -4,46 +4,19 @@ import { TableBody, TableCaption, TableCell, - TableFooter, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Download } from "lucide-react"; import Link from "next/link"; +import clientPromise from "@/lib/db"; -const downloads = [ - { - date: "2024-06-01", - fileName: "SVRJS_v1.0.0.zip", - version: "1.0.0", - fileSize: "15MB", - downloadLink: "/downloads/SVRJS_v1.0.0.zip", - }, - { - date: "2024-06-10", - fileName: "SVRJS_v1.1.0.zip", - version: "1.1.0", - fileSize: "18MB", - downloadLink: "/downloads/SVRJS_v1.1.0.zip", - }, - { - date: "2024-06-15", - fileName: "SVRJS_v1.2.0.zip", - version: "1.2.0", - fileSize: "20MB", - downloadLink: "/downloads/SVRJS_v1.2.0.zip", - }, - { - date: "2024-06-20", - fileName: "SVRJS_v1.3.0.zip", - version: "1.3.0", - fileSize: "22MB", - downloadLink: "/downloads/SVRJS_v1.3.0.zip", - }, -]; +const DownloadPage = async () => { + const client = await clientPromise; + const db = client.db("downloadsDatabase"); + const downloads = await db.collection("downloads").find().toArray(); -const DownloadPage = () => { return (
{ Date File Name Version - Download Link - File Size + File Size + Download Link - {downloads.map((download) => ( - - {download.date} - {download.fileName} - {download.version} - {download.fileSize} - - - - - - - ))} + {downloads + .slice() + .reverse() + .map((download: any) => ( + + {download.date} + {download.fileName} + {download.version} + {download.fileSize} + + + + + + + ))}
diff --git a/app/api/upload/route.ts b/app/api/upload/route.ts new file mode 100644 index 0000000..abe2283 --- /dev/null +++ b/app/api/upload/route.ts @@ -0,0 +1,20 @@ +import { NextResponse } from "next/server"; +import clientPromise from "@/lib/db"; + +export async function POST(request: Request) { + const body = await request.json(); + const { fileName, version, downloadLink, fileSize } = body; + + const client = await clientPromise; + const db = client.db("downloadsDatabase"); + + const result = await db.collection("downloads").insertOne({ + date: new Date().toISOString().split("T")[0], + fileName, + version, + downloadLink, + fileSize, + }); + + return NextResponse.json({ success: true, id: result.insertedId }); +} diff --git a/app/api/uploadthing/core.ts b/app/api/uploadthing/core.ts new file mode 100644 index 0000000..3a26bf3 --- /dev/null +++ b/app/api/uploadthing/core.ts @@ -0,0 +1,22 @@ +import { createUploadthing, type FileRouter } from "uploadthing/next"; +import { UploadThingError } from "uploadthing/server"; + +const f = createUploadthing(); + +// const auth = (req: Request) => ({ id: "fakeId" }); + +export const ourFileRouter = { + imageUploader: f({ "application/zip": { maxFileSize: "8MB" } }) + // .middleware(async ({ req }) => { + // const user = await auth(req); + // if (!user) throw new UploadThingError("Unauthorized"); + // return { userId: user.id }; + // }) + .onUploadComplete(async ({ metadata, file }) => { + // console.log("Upload complete for userId:", metadata.userId); + console.log("file url", file.url); + // return { uploadedBy: metadata.userId }; + }), +} satisfies FileRouter; + +export type OurFileRouter = typeof ourFileRouter; diff --git a/app/api/uploadthing/route.ts b/app/api/uploadthing/route.ts new file mode 100644 index 0000000..f8f1912 --- /dev/null +++ b/app/api/uploadthing/route.ts @@ -0,0 +1,6 @@ +import { createRouteHandler } from "uploadthing/next"; +import { ourFileRouter } from "./core"; + +export const { GET, POST } = createRouteHandler({ + router: ourFileRouter, +}); diff --git a/lib/db.ts b/lib/db.ts new file mode 100644 index 0000000..6e6ea2e --- /dev/null +++ b/lib/db.ts @@ -0,0 +1,24 @@ +import { MongoClient } from "mongodb"; + +if (!process.env.MONGODB_URI) { + throw new Error('Invalid/Missing environment variable: "MONGODB_URI"'); +} + +const uri = process.env.MONGODB_URI; +const options = {}; + +let client; +let clientPromise: Promise; + +if (process.env.NODE_ENV === "development") { + if (!(global as any)._mongoClientPromise) { + client = new MongoClient(uri!, options); + (global as any)._mongoClientPromise = client.connect(); + } + clientPromise = (global as any)._mongoClientPromise; +} else { + client = new MongoClient(uri!, options); + clientPromise = client.connect(); +} + +export default clientPromise; diff --git a/lib/uploadthing.ts b/lib/uploadthing.ts new file mode 100644 index 0000000..eded484 --- /dev/null +++ b/lib/uploadthing.ts @@ -0,0 +1,9 @@ +import { + generateUploadButton, + generateUploadDropzone, +} from "@uploadthing/react"; + +import type { OurFileRouter } from "@/app/api/uploadthing/core"; + +export const UploadButton = generateUploadButton(); +export const UploadDropzone = generateUploadDropzone(); diff --git a/lib/validations/validation.ts b/lib/validations/validation.ts index e67736c..4cbcaab 100644 --- a/lib/validations/validation.ts +++ b/lib/validations/validation.ts @@ -1,7 +1,8 @@ import { z } from "zod"; export const downloadSchema = z.object({ - username: z.string().min(2, { - message: "Username must be at least 2 characters.", - }), + fileName: z.string().nonempty(), + version: z.string().nonempty(), + downloadLink: z.string().url().nonempty(), + fileSize: z.string().nonempty(), }); diff --git a/package-lock.json b/package-lock.json index f0f2278..19cd20c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,12 +20,14 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/themes": "^3.0.5", "@types/cookie": "^0.6.0", + "@uploadthing/react": "^6.6.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cookie": "^0.6.0", "framer-motion": "^11.2.10", "lucide-react": "^0.394.0", "mini-svg-data-uri": "^1.4.4", + "mongoose": "^8.4.3", "next": "14.2.3", "next-themes": "^0.3.0", "react": "^18", @@ -34,6 +36,7 @@ "react-hook-form": "^7.52.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", + "uploadthing": "^6.12.0", "zod": "^3.23.8" }, "devDependencies": { @@ -69,6 +72,16 @@ "node": ">=6.9.0" } }, + "node_modules/@effect/schema": { + "version": "0.66.16", + "resolved": "https://registry.npmjs.org/@effect/schema/-/schema-0.66.16.tgz", + "integrity": "sha512-sT/k5NOgKslGPzs3DUaCFuM6g2JQoIIT8jpwEorAZooplPIMK2xIspr7ECz6pp6Dc7Wz/ppXGk7HVyGZQsIYEQ==", + "license": "MIT", + "peerDependencies": { + "effect": "^3.1.3", + "fast-check": "^3.13.2" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -332,6 +345,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", + "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@next/env": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz", @@ -2183,6 +2205,21 @@ "@types/react": "*" } }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@typescript-eslint/parser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", @@ -2316,6 +2353,74 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@uploadthing/dropzone": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@uploadthing/dropzone/-/dropzone-0.4.1.tgz", + "integrity": "sha512-RHSpo/2kg/mrRSYQA4EKlyvkOCYWOeE2+QQYW9YiUvWCuawnTfD7DQvk8RN/nYXi1Sw7/v0NegmQpiVELVGtnA==", + "license": "MIT", + "dependencies": { + "file-selector": "^0.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "solid-js": "^1.7.11", + "svelte": "^4.2.12", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "solid-js": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@uploadthing/mime-types": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@uploadthing/mime-types/-/mime-types-0.2.10.tgz", + "integrity": "sha512-kz3F0oEgAyts25NAGXlUBCWh3mXonbSOQJFGFMawHuIgbUbnzXbe4w5WI+0XdneCbjNmikfWrdWrs8m/7HATfQ==", + "license": "MIT" + }, + "node_modules/@uploadthing/react": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@uploadthing/react/-/react-6.6.0.tgz", + "integrity": "sha512-jLN4Oy21d0n8F6CNPl9qjEu0/Q1rnddSxny/02Lm89L/sYuR4RXfk1vBgBGPAGXBak0BO9z5eEmYURLrXXUAJQ==", + "license": "MIT", + "dependencies": { + "@uploadthing/dropzone": "0.4.1", + "@uploadthing/shared": "6.7.5", + "file-selector": "^0.6.0", + "tailwind-merge": "^2.2.1" + }, + "peerDependencies": { + "next": "*", + "react": "^17.0.2 || ^18.0.0", + "uploadthing": "6.12.0" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } + } + }, + "node_modules/@uploadthing/shared": { + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@uploadthing/shared/-/shared-6.7.5.tgz", + "integrity": "sha512-BZXzvh6zGEt4ip//mxfXdRTNWYw9XJ6tommL6A1TEo2l8jvdNbUpPUwXnMVWBMwio2b48BO7D9V3siYIKMD4pg==", + "license": "MIT", + "dependencies": { + "@uploadthing/mime-types": "0.2.10", + "effect": "^3.1.0", + "std-env": "^3.7.0" + } + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -2670,6 +2775,15 @@ "node": ">=8" } }, + "node_modules/bson": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", + "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -2854,6 +2968,15 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -2953,7 +3076,6 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3059,6 +3181,12 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/effect": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.3.5.tgz", + "integrity": "sha512-ehDpb+3zRTYsCqDWY32rT4oxtG0BJ797+HSog+FPjiWKjNxnPgpslUIQha8CoxqFZln2ZeBRv00tzGIhUAQKsw==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -3659,6 +3787,28 @@ "node": ">=0.10.0" } }, + "node_modules/fast-check": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.19.0.tgz", + "integrity": "sha512-CO2JX/8/PT9bDGO1iXa5h5ey1skaKI1dvecERyhH4pp3PGjwd3KIjMAXEg79Ps9nclsdt4oPbfqiAnLU0EwrAQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3723,6 +3873,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4682,6 +4844,15 @@ "node": ">=4.0" } }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4783,6 +4954,12 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4841,11 +5018,115 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mongodb": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.6.2.tgz", + "integrity": "sha512-ZF9Ugo2JCG/GfR7DEb4ypfyJJyiKbg5qBYKRintebj8+DNS33CyGMkWbrS9lara+u+h+yEOGSRiLhFO/g1s1aw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/mongoose": { + "version": "8.4.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.4.3.tgz", + "integrity": "sha512-GxPVLD+I/dxVkgcts2r2QmJJvS62/++btVj3RFt8YnHt+DSOp1Qjj62YEvgZaElwIOTcc4KGJM95X5LlrU1qQg==", + "license": "MIT", + "dependencies": { + "bson": "^6.7.0", + "kareem": "2.6.3", + "mongodb": "6.6.2", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -5433,11 +5714,26 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5871,6 +6167,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -5899,6 +6201,21 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "license": "MIT" + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -6254,6 +6571,18 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -6419,6 +6748,48 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/uploadthing": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/uploadthing/-/uploadthing-6.12.0.tgz", + "integrity": "sha512-uoWG1riH6z2IHCcbMo3xnGe6p/+sx2PPOOLOsk5DeqGv5HtlY7ISauFFRXW8H+jdhevZm1n/j4Je/Z+bbIziSg==", + "license": "MIT", + "dependencies": { + "@effect/schema": "^0.66.12", + "@uploadthing/mime-types": "0.2.10", + "@uploadthing/shared": "6.7.5", + "consola": "^3.2.3", + "effect": "^3.1.0", + "fast-check": "^3.18.0", + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=18.13.0" + }, + "peerDependencies": { + "express": "*", + "fastify": "*", + "h3": "*", + "next": "*", + "tailwindcss": "*" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + }, + "fastify": { + "optional": true + }, + "h3": { + "optional": true + }, + "next": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6474,6 +6845,28 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 7f3de55..f44a3cf 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,14 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/themes": "^3.0.5", "@types/cookie": "^0.6.0", + "@uploadthing/react": "^6.6.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cookie": "^0.6.0", "framer-motion": "^11.2.10", "lucide-react": "^0.394.0", "mini-svg-data-uri": "^1.4.4", + "mongoose": "^8.4.3", "next": "14.2.3", "next-themes": "^0.3.0", "react": "^18", @@ -35,6 +37,7 @@ "react-hook-form": "^7.52.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", + "uploadthing": "^6.12.0", "zod": "^3.23.8" }, "devDependencies": {