From d920f4fed49270d73c06b1d8524ca46c975f234c Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Sat, 19 Apr 2025 13:47:32 +0530 Subject: [PATCH 1/2] Fixed signing up from app; UI upliftment for billing and landing screen; --- apps/api/__tests__/apikey/handlers.test.ts | 37 --- apps/api/__tests__/media/handlers.test.ts | 102 +++++++ .../{handlers.ts => handlers.ts.notused} | 0 apps/api/src/apikey/queries.ts | 20 +- apps/api/src/config/constants.ts | 9 +- apps/api/src/index.ts | 7 + apps/api/src/media/handlers.ts | 23 +- apps/api/src/services/s3.ts | 31 +- .../{middleware.ts => middleware.ts.notused} | 0 apps/web/app/account/billing/page.tsx | 177 ++++++----- apps/web/app/login/page.tsx | 8 +- apps/web/app/page.tsx | 48 ++- apps/web/auth.ts | 12 +- apps/web/components/new-app-button.tsx | 2 +- apps/web/components/ui/card.tsx | 86 ++++++ apps/web/package.json | 2 +- packages/models/src/constants.ts | 7 + packages/models/src/subscription-status.ts | 8 +- pnpm-lock.yaml | 283 +++++++++--------- 19 files changed, 555 insertions(+), 307 deletions(-) create mode 100644 apps/api/__tests__/media/handlers.test.ts rename apps/api/src/apikey/{handlers.ts => handlers.ts.notused} (100%) rename apps/api/src/subscription/{middleware.ts => middleware.ts.notused} (100%) create mode 100644 apps/web/components/ui/card.tsx diff --git a/apps/api/__tests__/apikey/handlers.test.ts b/apps/api/__tests__/apikey/handlers.test.ts index 2c7c1ae7..72df2e17 100644 --- a/apps/api/__tests__/apikey/handlers.test.ts +++ b/apps/api/__tests__/apikey/handlers.test.ts @@ -1,44 +1,7 @@ import test, { afterEach, describe, mock } from "node:test"; -import { createApikey } from "../../src/apikey/handlers"; -import assert from "node:assert"; -import queries from "../../src/apikey/queries"; describe("API key test suite", () => { afterEach(() => { mock.restoreAll(); }); - - test("Create API key throws an error if name is empty", async (t) => { - const req = { - body: {}, - }; - const res = { - status: () => ({ - json: (data: any) => data, - }), - }; - const response = await createApikey(req, res, () => {}); - assert.strictEqual(response.error, "Name is required"); - }); - - test("Create API succeeds if name is provided.", async (t) => { - const req = { - body: { - name: "Test API", - }, - user: { - id: "123", - }, - }; - const res = { - status: () => ({ - json: (data: any) => data, - }), - }; - mock.method(queries, "createApiKey").mock.mockImplementation( - async () => ({ key: "123" }), - ); - const response = await createApikey(req, res, () => {}); - assert.strictEqual(response.key, "123"); - }); }); diff --git a/apps/api/__tests__/media/handlers.test.ts b/apps/api/__tests__/media/handlers.test.ts new file mode 100644 index 00000000..a0c1e9d1 --- /dev/null +++ b/apps/api/__tests__/media/handlers.test.ts @@ -0,0 +1,102 @@ +import { Constants } from "@medialit/models"; +import test, { afterEach, describe, mock } from "node:test"; +import { uploadMedia } from "../../src/media/handlers"; +import assert from "node:assert"; +import { FILE_SIZE_EXCEEDED } from "../../src/config/strings"; +import mediaService from "../../src/media/service"; + +describe("Media handlers", () => { + afterEach(() => { + mock.restoreAll(); + }); + + test("should reject upload if file size exceeds limit for non-subscribed user", async () => { + const req = { + files: { + file: { + size: 100000000, // 100MB + }, + }, + user: { + id: "123", + subscriptionStatus: Constants.SubscriptionStatus.NOT_SUBSCRIBED, + }, + socket: { + setTimeout: () => {}, + }, + }; + + const res = { + status: (code: number) => ({ + json: (data: any) => ({ code, data }), + }), + }; + + const response = await uploadMedia(req, res, () => {}); + assert.strictEqual(response.code, 400); + assert.ok(response.data.error.includes(FILE_SIZE_EXCEEDED)); + }); + + test("should reject upload if file size exceeds limit for subscribed user", async () => { + const req = { + files: { + file: { + size: 2147483648 + 1, // 2GB + 1 byte + }, + }, + user: { + id: "123", + subscriptionStatus: Constants.SubscriptionStatus.SUBSCRIBED, + }, + socket: { + setTimeout: () => {}, + }, + }; + + const res = { + status: (code: number) => ({ + json: (data: any) => ({ code, data }), + }), + }; + + const response = await uploadMedia(req, res, () => {}); + assert.strictEqual(response.code, 400); + assert.ok(response.data.error.includes(FILE_SIZE_EXCEEDED)); + }); + + test("should allow larger file upload for subscribed user", async () => { + const req = { + files: { + file: { + size: 100000000, // 100MB - within subscribed limit + }, + }, + user: { + id: "123", + subscriptionStatus: Constants.SubscriptionStatus.SUBSCRIBED, + }, + socket: { + setTimeout: () => {}, + }, + body: {}, + query: {}, + }; + + const res = { + status: (code: number) => ({ + json: (data: any) => ({ code, data }), + }), + }; + + mock.method(mediaService, "upload").mock.mockImplementation( + async () => "test-media-id", + ); + + mock.method(mediaService, "getMediaDetails").mock.mockImplementation( + async () => ({ id: "test-media-id" }), + ); + + const response = await uploadMedia(req, res, () => {}); + assert.strictEqual(response.code, 200); + }); +}); diff --git a/apps/api/src/apikey/handlers.ts b/apps/api/src/apikey/handlers.ts.notused similarity index 100% rename from apps/api/src/apikey/handlers.ts rename to apps/api/src/apikey/handlers.ts.notused diff --git a/apps/api/src/apikey/queries.ts b/apps/api/src/apikey/queries.ts index d8220e1c..a22dcc2a 100644 --- a/apps/api/src/apikey/queries.ts +++ b/apps/api/src/apikey/queries.ts @@ -52,19 +52,19 @@ export async function getApiKeyByUserId( return result; } -export async function deleteApiKey( - userId: string, - keyId: string, -): Promise { - await ApikeyModel.deleteOne({ - key: keyId, - userId, - }); -} +// export async function deleteApiKey( +// userId: string, +// keyId: string, +// ): Promise { +// await ApikeyModel.deleteOne({ +// key: keyId, +// userId, +// }); +// } export default { createApiKey, getApiKeyUsingKeyId, getApiKeyByUserId, - deleteApiKey, + // deleteApiKey, }; diff --git a/apps/api/src/config/constants.ts b/apps/api/src/config/constants.ts index 14191f1d..665b3555 100644 --- a/apps/api/src/config/constants.ts +++ b/apps/api/src/config/constants.ts @@ -3,7 +3,14 @@ export const appName = process.env.APP_NAME || "MediaLit"; export const jwtSecret = process.env.JWT_SECRET || "r@nd0m1e"; export const jwtExpire = process.env.JWT_EXPIRES_IN || "1d"; export const tempFileDirForUploads = process.env.TEMP_FILE_DIR_FOR_UPLOADS; -export const maxFileUploadSize = process.env.MAX_UPLOAD_SIZE || 2147483648; +export const maxFileUploadSizeSubscribed = process.env + .MAX_UPLOAD_SIZE_SUBSCRIBED + ? +process.env.MAX_UPLOAD_SIZE_SUBSCRIBED + : 2147483648; +export const maxFileUploadSizeNotSubscribed = process.env + .MAX_UPLOAD_SIZE_NOT_SUBSCRIBED + ? +process.env.MAX_UPLOAD_SIZE_NOT_SUBSCRIBED + : 52428800; export const PRESIGNED_URL_VALIDITY_MINUTES = 5; export const PRESIGNED_URL_LENGTH = 100; export const MEDIA_ID_LENGTH = 40; diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 9780d824..804d8264 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -20,6 +20,13 @@ app.set("trust proxy", process.env.ENABLE_TRUST_PROXY === "true"); app.use(express.json()); +app.get("/health", (req, res) => { + res.status(200).json({ + status: "ok", + uptime: process.uptime(), + }); +}); + app.use("/settings/media", mediaSettingsRoutes(passport)); app.use("/media/presigned", presignedUrlRoutes); app.use("/media", mediaRoutes); diff --git a/apps/api/src/media/handlers.ts b/apps/api/src/media/handlers.ts index c1784e3d..ab5e658f 100644 --- a/apps/api/src/media/handlers.ts +++ b/apps/api/src/media/handlers.ts @@ -1,5 +1,8 @@ import Joi from "joi"; -import { maxFileUploadSize } from "../config/constants"; +import { + maxFileUploadSizeNotSubscribed, + maxFileUploadSizeSubscribed, +} from "../config/constants"; import { FILE_IS_REQUIRED, FILE_SIZE_EXCEEDED, @@ -10,6 +13,7 @@ import logger from "../services/log"; import { Request } from "express"; import mediaService from "./service"; import { getMediaCount as getCount, getTotalSpace } from "./queries"; +import { Constants } from "@medialit/models"; function validateUploadOptions(req: Request): Joi.ValidationResult { const uploadSchema = Joi.object({ @@ -21,6 +25,14 @@ function validateUploadOptions(req: Request): Joi.ValidationResult { return uploadSchema.validate({ caption, access, group }); } +function getMaxFileUploadSize(req: any): number { + const isSubscribed = + req.user.subscriptionStatus === Constants.SubscriptionStatus.SUBSCRIBED; + return isSubscribed + ? maxFileUploadSizeSubscribed + : maxFileUploadSizeNotSubscribed; +} + export async function uploadMedia( req: any, res: any, @@ -32,8 +44,13 @@ export async function uploadMedia( return res.status(400).json({ error: FILE_IS_REQUIRED }); } - if (req.files.file.size > maxFileUploadSize) { - return res.status(400).json({ error: FILE_SIZE_EXCEEDED }); + const allowedFileSize = getMaxFileUploadSize(req); + if (req.files.file.size > allowedFileSize) { + return res + .status(400) + .json({ + error: `${FILE_SIZE_EXCEEDED}. Allowed: ${allowedFileSize} bytes`, + }); } const { error } = validateUploadOptions(req); diff --git a/apps/api/src/services/s3.ts b/apps/api/src/services/s3.ts index 16a11f44..8e935a81 100644 --- a/apps/api/src/services/s3.ts +++ b/apps/api/src/services/s3.ts @@ -37,20 +37,27 @@ export interface PresignedURLParams { mimetype?: string; } -const s3Client = new S3Client({ - region: cloudRegion, - endpoint: cloudEndpoint, - credentials: { - accessKeyId: cloudKey, - secretAccessKey: cloudSecret, - }, -}); +let s3Client: S3Client | null = null; + +const getS3Client = () => { + if (!s3Client) { + s3Client = new S3Client({ + region: cloudRegion, + endpoint: cloudEndpoint, + credentials: { + accessKeyId: cloudKey, + secretAccessKey: cloudSecret, + }, + }); + } + return s3Client; +}; export const putObject = async (params: UploadParams) => { const command = new PutObjectCommand( Object.assign({}, { Bucket: cloudBucket }, params), ); - const response = await s3Client.send(command); + const response = await getS3Client().send(command); return response; }; @@ -58,7 +65,7 @@ export const deleteObject = async (params: DeleteParams) => { const command = new DeleteObjectCommand( Object.assign({}, { Bucket: cloudBucket }, params), ); - const response = await s3Client.send(command); + const response = await getS3Client().send(command); return response; }; @@ -66,7 +73,7 @@ export const getObjectTagging = async (params: { Key: string }) => { const command = new GetObjectTaggingCommand( Object.assign({}, { Bucket: cloudBucket }, params), ); - const response = await s3Client.send(command); + const response = await getS3Client().send(command); return response; }; @@ -75,7 +82,7 @@ export const generateSignedUrl = async (key: string): Promise => { Bucket: cloudBucket, Key: key, }); - const url = await getS3SignedUrl(s3Client, command); + const url = await getS3SignedUrl(getS3Client(), command); return url; }; diff --git a/apps/api/src/subscription/middleware.ts b/apps/api/src/subscription/middleware.ts.notused similarity index 100% rename from apps/api/src/subscription/middleware.ts rename to apps/api/src/subscription/middleware.ts.notused diff --git a/apps/web/app/account/billing/page.tsx b/apps/web/app/account/billing/page.tsx index 9c8c9953..c0d778ed 100644 --- a/apps/web/app/account/billing/page.tsx +++ b/apps/web/app/account/billing/page.tsx @@ -11,18 +11,26 @@ import { auth } from "@/auth"; import { getSubscriber } from "@/app/actions"; import { redirect } from "next/navigation"; import { User } from "@medialit/models"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; const pricingPlans = [ { name: "Basic", description: "Get started for free", price: 0, - icon: , + icon: , features: [ "1 GB of storage", - "Unlimited upload/download", + "50 MB maximum file size", + "Unlimited upload and download", "Private files", - "500 MB maximum file size", ], isSecondary: true, }, @@ -30,8 +38,12 @@ const pricingPlans = [ name: "Pro", description: "More storage for teams that want more", price: 10, - icon: , - features: ["Everything in the Basic plan", "100 GB of storage"], + icon: , + features: [ + "Everything in the Basic plan", + "100 GB of storage", + "2 GB maximum file size", + ], }, ]; @@ -60,86 +72,99 @@ const PricingPane = async ({ } return ( -
-
-
{name}
-

{description}

-
- ${price} - /month + + + {name} + {description} +
+ ${price} + /month
-
+ + +
{features.map((feature) => (
{icon}

{feature}

))}
-
- - {name === "Basic" - ? ["not-subscribed", "expired"].includes( - user.subscriptionStatus, - ) && ( - <> - {LEMONSQUEEZY_STORE_ID && LEMONSQUEEZY_PRODUCT_ID && ( - - {user.subscriptionStatus === "not-subscribed" - ? "Current plan " - : "Downgrade to free"} - - )} - - ) - : ["not-subscribed", "expired"].includes( - user.subscriptionStatus, - ) && ( - <> - {LEMONSQUEEZY_STORE_ID && LEMONSQUEEZY_PRODUCT_ID && ( - - Subscribe - - )} - - )} + + + {name === "Basic" + ? ["not-subscribed", "expired"].includes( + user.subscriptionStatus, + ) && ( + <> + {LEMONSQUEEZY_STORE_ID && + LEMONSQUEEZY_PRODUCT_ID && ( + + {user.subscriptionStatus === + "not-subscribed" + ? "Current plan" + : "Downgrade to free"} + + )} + + ) + : ["not-subscribed", "expired"].includes( + user.subscriptionStatus, + ) && ( + <> + {LEMONSQUEEZY_STORE_ID && + LEMONSQUEEZY_PRODUCT_ID && ( + + Subscribe + + )} + + )} - {["subscribed", "paused"].includes(user.subscriptionStatus) && ( - - )} + {["subscribed", "paused"].includes(user.subscriptionStatus) && ( + + )} - {user.subscriptionStatus === "cancelled" && ( - - )} -
+ {user.subscriptionStatus === "cancelled" && ( + + )} + + ); }; @@ -154,11 +179,9 @@ const Billing = async () => { uploads so that you focus on your users.

-
+
{pricingPlans.map((pricingPlan) => ( - <> - - + ))}
diff --git a/apps/web/app/login/page.tsx b/apps/web/app/login/page.tsx index 5e42d0fe..2a3b7857 100644 --- a/apps/web/app/login/page.tsx +++ b/apps/web/app/login/page.tsx @@ -16,13 +16,13 @@ export default async function LoginPage() {

By signing in, you agree to our{" "} - + Terms - {" "} + {" "} and{" "} - + Privacy policy - + .

diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 303fa318..91d51fd7 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -3,6 +3,8 @@ import { getApiKeys } from "./actions"; import { redirect } from "next/navigation"; import Link from "next/link"; import NewApp from "@/components/new-app-button"; +import { FolderPlus } from "lucide-react"; +import { Card, CardContent } from "@/components/ui/card"; export default async function Home() { const session = await auth(); @@ -14,25 +16,39 @@ export default async function Home() { return ( <> -
+
Your apps
-
-
- {apiKeys?.map((apikey: any, index: number) => ( -
-
- - {apikey.name || "Untitled"} - -
-
- ))} -
+
+ {apiKeys?.length > 0 ? ( +
+ {apiKeys.map((apikey: any) => ( + + + + + {apikey.name || "Untitled"} + + + + + ))} +
+ ) : ( +
+ +

+ No apps yet +

+

+ Create your first app to start uploading files +

+
+ )}
); diff --git a/apps/web/auth.ts b/apps/web/auth.ts index 8e210456..8da52e29 100644 --- a/apps/web/auth.ts +++ b/apps/web/auth.ts @@ -48,7 +48,17 @@ export const { auth, signIn, signOut, handlers } = NextAuth({ }); if (!user) { - user = await User.create({ email: sanitizedEmail }); + user = await User.create({ + email: sanitizedEmail, + active: true, + subscriptionEndsAfter: new Date( + new Date().setFullYear( + new Date().getFullYear() + 100, + ), + ), + subscriptionStatus: + Constants.SubscriptionStatus.NOT_SUBSCRIBED, + }); await Apikey.create({ name: Constants.internalApikeyName, key: getUniqueId(), diff --git a/apps/web/components/new-app-button.tsx b/apps/web/components/new-app-button.tsx index 7af2b17f..4dcd573b 100644 --- a/apps/web/components/new-app-button.tsx +++ b/apps/web/components/new-app-button.tsx @@ -18,7 +18,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useToast } from "@/components/ui/use-toast"; import { ToastAction } from "@/components/ui/toast"; -import { Button } from "./ui/button"; +import { Button } from "@/components/ui/button"; import { createNewApiKey } from "@/app/actions"; export default function NewApp() { diff --git a/apps/web/components/ui/card.tsx b/apps/web/components/ui/card.tsx new file mode 100644 index 00000000..5a9f1c68 --- /dev/null +++ b/apps/web/components/ui/card.tsx @@ -0,0 +1,86 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/apps/web/package.json b/apps/web/package.json index 63768c41..e9202123 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -26,7 +26,7 @@ "clsx": "^2.1.0", "lucide-react": "^0.487.0", "mongoose": "^8.0.1", - "next": "15.2.4", + "next": "^15.3.1", "next-auth": "5.0.0-beta.25", "next-themes": "^0.2.1", "nodemailer": "^6.7.2", diff --git a/packages/models/src/constants.ts b/packages/models/src/constants.ts index d12541c6..145a44da 100644 --- a/packages/models/src/constants.ts +++ b/packages/models/src/constants.ts @@ -1,2 +1,9 @@ export const apikeyRestriction = ["referrer", "ipaddress", "custom"]; export const internalApikeyName = "internal-apikey"; +export const SubscriptionStatus = { + NOT_SUBSCRIBED: "not-subscribed", + SUBSCRIBED: "subscribed", + CANCELLED: "cancelled", + PAUSED: "paused", + EXPIRED: "expired", +} as const; diff --git a/packages/models/src/subscription-status.ts b/packages/models/src/subscription-status.ts index 595db569..56592331 100644 --- a/packages/models/src/subscription-status.ts +++ b/packages/models/src/subscription-status.ts @@ -1,6 +1,4 @@ +import { Constants } from "."; + export type SubscriptionStatus = - | "not-subscribed" - | "subscribed" - | "cancelled" - | "paused" - | "expired"; + (typeof Constants.SubscriptionStatus)[keyof typeof Constants.SubscriptionStatus]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4399d1e2..410e4a8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,14 +199,14 @@ importers: specifier: ^8.0.1 version: 8.13.2 next: - specifier: 15.2.4 - version: 15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^15.3.1 + version: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.10.0)(react@19.1.0) + version: 5.0.0-beta.25(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.10.0)(react@19.1.0) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 0.2.1(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) nodemailer: specifier: ^6.7.2 version: 6.10.0 @@ -899,107 +899,112 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/sharp-darwin-arm64@0.34.1': + resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.1': + resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.1.0': + resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.1.0': + resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.1.0': + resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.1.0': + resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.1.0': + resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.1.0': + resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.1.0': + resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.1.0': + resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.1': + resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.1': + resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-s390x@0.34.1': + resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.1': + resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.1': + resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.1': + resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.1': + resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-ia32@0.34.1': + resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.1': + resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1081,56 +1086,56 @@ packages: '@napi-rs/wasm-runtime@0.2.8': resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==} - '@next/env@15.2.4': - resolution: {integrity: sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==} + '@next/env@15.3.1': + resolution: {integrity: sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ==} '@next/eslint-plugin-next@15.2.4': resolution: {integrity: sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==} - '@next/swc-darwin-arm64@15.2.4': - resolution: {integrity: sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==} + '@next/swc-darwin-arm64@15.3.1': + resolution: {integrity: sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.2.4': - resolution: {integrity: sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==} + '@next/swc-darwin-x64@15.3.1': + resolution: {integrity: sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.2.4': - resolution: {integrity: sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==} + '@next/swc-linux-arm64-gnu@15.3.1': + resolution: {integrity: sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.2.4': - resolution: {integrity: sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==} + '@next/swc-linux-arm64-musl@15.3.1': + resolution: {integrity: sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.2.4': - resolution: {integrity: sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==} + '@next/swc-linux-x64-gnu@15.3.1': + resolution: {integrity: sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.2.4': - resolution: {integrity: sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==} + '@next/swc-linux-x64-musl@15.3.1': + resolution: {integrity: sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.2.4': - resolution: {integrity: sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==} + '@next/swc-win32-arm64-msvc@15.3.1': + resolution: {integrity: sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.2.4': - resolution: {integrity: sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==} + '@next/swc-win32-x64-msvc@15.3.1': + resolution: {integrity: sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -4250,8 +4255,8 @@ packages: react: '*' react-dom: '*' - next@15.2.4: - resolution: {integrity: sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==} + next@15.3.1: + resolution: {integrity: sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -5015,8 +5020,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.1: + resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@1.2.0: @@ -6704,79 +6709,82 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/sharp-darwin-arm64@0.34.1': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.1.0 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.1': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.1.0 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.1.0': optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.1.0': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.1.0': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm@1.1.0': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-ppc64@1.1.0': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-s390x@1.1.0': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-x64@1.1.0': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.1.0': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-x64@1.1.0': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-linux-arm64@0.34.1': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-arm64': 1.1.0 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-arm@0.34.1': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm': 1.1.0 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-s390x@0.34.1': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.1.0 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-x64@0.34.1': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.1.0 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.1': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.1': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.1.0 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.34.1': dependencies: '@emnapi/runtime': 1.4.0 optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.1': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.1': optional: true '@isaacs/cliui@8.0.2': @@ -6870,9 +6878,7 @@ snapshots: source-map: 0.6.1 string-length: 2.0.0 transitivePeerDependencies: - - bufferutil - supports-color - - utf-8-validate '@jest/source-map@24.9.0': dependencies: @@ -6973,34 +6979,34 @@ snapshots: '@tybys/wasm-util': 0.9.0 optional: true - '@next/env@15.2.4': {} + '@next/env@15.3.1': {} '@next/eslint-plugin-next@15.2.4': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.2.4': + '@next/swc-darwin-arm64@15.3.1': optional: true - '@next/swc-darwin-x64@15.2.4': + '@next/swc-darwin-x64@15.3.1': optional: true - '@next/swc-linux-arm64-gnu@15.2.4': + '@next/swc-linux-arm64-gnu@15.3.1': optional: true - '@next/swc-linux-arm64-musl@15.2.4': + '@next/swc-linux-arm64-musl@15.3.1': optional: true - '@next/swc-linux-x64-gnu@15.2.4': + '@next/swc-linux-x64-gnu@15.3.1': optional: true - '@next/swc-linux-x64-musl@15.2.4': + '@next/swc-linux-x64-musl@15.3.1': optional: true - '@next/swc-win32-arm64-msvc@15.2.4': + '@next/swc-win32-arm64-msvc@15.3.1': optional: true - '@next/swc-win32-x64-msvc@15.2.4': + '@next/swc-win32-x64-msvc@15.3.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -10202,9 +10208,7 @@ snapshots: pretty-format: 24.9.0 throat: 4.1.0 transitivePeerDependencies: - - bufferutil - supports-color - - utf-8-validate jest-leak-detector@24.9.0: dependencies: @@ -10800,23 +10804,23 @@ snapshots: negotiator@0.6.3: {} - next-auth@5.0.0-beta.25(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.10.0)(react@19.1.0): + next-auth@5.0.0-beta.25(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.10.0)(react@19.1.0): dependencies: '@auth/core': 0.37.2(nodemailer@6.10.0) - next: 15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 optionalDependencies: nodemailer: 6.10.0 - next-themes@0.2.1(next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next-themes@0.2.1(next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - next: 15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - next@15.2.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next@15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - '@next/env': 15.2.4 + '@next/env': 15.3.1 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 @@ -10826,15 +10830,15 @@ snapshots: react-dom: 19.1.0(react@19.1.0) styled-jsx: 5.1.6(react@19.1.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.2.4 - '@next/swc-darwin-x64': 15.2.4 - '@next/swc-linux-arm64-gnu': 15.2.4 - '@next/swc-linux-arm64-musl': 15.2.4 - '@next/swc-linux-x64-gnu': 15.2.4 - '@next/swc-linux-x64-musl': 15.2.4 - '@next/swc-win32-arm64-msvc': 15.2.4 - '@next/swc-win32-x64-msvc': 15.2.4 - sharp: 0.33.5 + '@next/swc-darwin-arm64': 15.3.1 + '@next/swc-darwin-x64': 15.3.1 + '@next/swc-linux-arm64-gnu': 15.3.1 + '@next/swc-linux-arm64-musl': 15.3.1 + '@next/swc-linux-x64-gnu': 15.3.1 + '@next/swc-linux-x64-musl': 15.3.1 + '@next/swc-win32-arm64-msvc': 15.3.1 + '@next/swc-win32-x64-msvc': 15.3.1 + sharp: 0.34.1 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -11600,31 +11604,32 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.33.5: + sharp@0.34.1: dependencies: color: 4.2.3 detect-libc: 2.0.3 semver: 7.7.1 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.1 + '@img/sharp-darwin-x64': 0.34.1 + '@img/sharp-libvips-darwin-arm64': 1.1.0 + '@img/sharp-libvips-darwin-x64': 1.1.0 + '@img/sharp-libvips-linux-arm': 1.1.0 + '@img/sharp-libvips-linux-arm64': 1.1.0 + '@img/sharp-libvips-linux-ppc64': 1.1.0 + '@img/sharp-libvips-linux-s390x': 1.1.0 + '@img/sharp-libvips-linux-x64': 1.1.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + '@img/sharp-linux-arm': 0.34.1 + '@img/sharp-linux-arm64': 0.34.1 + '@img/sharp-linux-s390x': 0.34.1 + '@img/sharp-linux-x64': 0.34.1 + '@img/sharp-linuxmusl-arm64': 0.34.1 + '@img/sharp-linuxmusl-x64': 0.34.1 + '@img/sharp-wasm32': 0.34.1 + '@img/sharp-win32-ia32': 0.34.1 + '@img/sharp-win32-x64': 0.34.1 optional: true shebang-command@1.2.0: From c55bcfc4f7340f374863a9c83cea69d409e9ca5c Mon Sep 17 00:00:00 2001 From: Rajat Saxena Date: Sat, 19 Apr 2025 13:51:07 +0530 Subject: [PATCH 2/2] Prettier fixes --- apps/api/src/media/handlers.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/api/src/media/handlers.ts b/apps/api/src/media/handlers.ts index ab5e658f..d3e581bd 100644 --- a/apps/api/src/media/handlers.ts +++ b/apps/api/src/media/handlers.ts @@ -46,11 +46,9 @@ export async function uploadMedia( const allowedFileSize = getMaxFileUploadSize(req); if (req.files.file.size > allowedFileSize) { - return res - .status(400) - .json({ - error: `${FILE_SIZE_EXCEEDED}. Allowed: ${allowedFileSize} bytes`, - }); + return res.status(400).json({ + error: `${FILE_SIZE_EXCEEDED}. Allowed: ${allowedFileSize} bytes`, + }); } const { error } = validateUploadOptions(req);