diff --git a/examples/playground14/e2e/cloudflare.spec.ts b/examples/playground14/e2e/cloudflare.spec.ts index fd3615521..7a9a8b9be 100644 --- a/examples/playground14/e2e/cloudflare.spec.ts +++ b/examples/playground14/e2e/cloudflare.spec.ts @@ -5,6 +5,7 @@ */ import { test, expect } from "@playwright/test"; +import sharp from "sharp"; test.describe("playground/cloudflare", () => { test("NextConfig", async ({ page }) => { @@ -21,20 +22,24 @@ test.describe("playground/cloudflare", () => { test.describe("remotePatterns", () => { test("fetch an image allowed by remotePatterns", async ({ page }) => { - const res = await page.request.get("/_next/image?url=https://avatars.githubusercontent.com/u/248818"); + const res = await page.request.get( + "/_next/image?url=https://avatars.githubusercontent.com/u/248818&w=256&q=75" + ); expect(res.status()).toBe(200); expect(res.headers()).toMatchObject({ "content-type": "image/jpeg" }); }); test("400 when fetching an image disallowed by remotePatterns", async ({ page }) => { - const res = await page.request.get("/_next/image?url=https://avatars.githubusercontent.com/u/248817"); + const res = await page.request.get( + "/_next/image?url=https://avatars.githubusercontent.com/u/248817&w=256&q=75" + ); expect(res.status()).toBe(400); }); }); test.describe("localPatterns", () => { test("fetch an image allowed by localPatterns", async ({ page }) => { - const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes"); + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=75"); expect(res.status()).toBe(200); expect(res.headers()).toMatchObject({ "content-type": "image/webp" }); }); @@ -42,15 +47,39 @@ test.describe("playground/cloudflare", () => { test("400 when fetching an image disallowed by localPatterns with wrong query parameter", async ({ page, }) => { - const res = await page.request.get("/_next/image?url=/snipp/snipp?iscute=no"); + const res = await page.request.get("/_next/image?url=/snipp/snipp?iscute=no&w=256&q=75"); expect(res.status()).toBe(400); }); test("400 when fetching an image disallowed by localPatterns without query parameter", async ({ page, }) => { - const res = await page.request.get("/_next/image?url=/snipp/snipp"); + const res = await page.request.get("/_next/image?url=/snipp/snipp&w=256&q=75"); expect(res.status()).toBe(400); }); }); + + test.describe("imageSizes", () => { + test("400 when fetching an image with unsupported width value", async ({ page }) => { + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=100&q=75"); + expect(res.status()).toBe(400); + }); + }); + + test.describe("qualities", () => { + test("400 when fetching an image with unsupported quality value", async ({ page }) => { + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=100"); + expect(res.status()).toBe(400); + }); + }); + + test.describe('"w" parameter', () => { + test("Image is shrunk to target width", async ({ page }) => { + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=75"); + expect(res.status()).toBe(200); + const buffer = await res.body(); + const metadata = await sharp(buffer).metadata(); + expect(metadata.width).toBe(256); + }); + }); }); diff --git a/examples/playground14/package.json b/examples/playground14/package.json index 8caf82f0c..276eff66f 100644 --- a/examples/playground14/package.json +++ b/examples/playground14/package.json @@ -24,6 +24,7 @@ "@opennextjs/cloudflare": "workspace:*", "@playwright/test": "catalog:", "@types/node": "catalog:", + "sharp": "^0.34.5", "wrangler": "catalog:" } } diff --git a/examples/playground14/wrangler.jsonc b/examples/playground14/wrangler.jsonc index f7c13c4e8..aa2a649f7 100644 --- a/examples/playground14/wrangler.jsonc +++ b/examples/playground14/wrangler.jsonc @@ -18,5 +18,8 @@ "hello": "Hello World from the cloudflare context!", "PROCESS_ENV_VAR": "process.env", "NEXT_INC_CACHE_KV_PREFIX": "custom_prefix" + }, + "images": { + "binding": "IMAGES" } } diff --git a/examples/playground15/next.config.ts b/examples/playground15/next.config.ts index 5a9fdb889..fa7885f61 100644 --- a/examples/playground15/next.config.ts +++ b/examples/playground15/next.config.ts @@ -12,6 +12,9 @@ const nextConfig: NextConfig = { }, deploymentId: getDeploymentId(), trailingSlash: true, + images: { + formats: ["image/avif", "image/webp"], + }, }; export default nextConfig; diff --git a/examples/playground15/wrangler.jsonc b/examples/playground15/wrangler.jsonc index 56965f57b..1c6c3718e 100644 --- a/examples/playground15/wrangler.jsonc +++ b/examples/playground15/wrangler.jsonc @@ -44,5 +44,8 @@ "database_id": "db_id", "database_name": "db_name" } - ] + ], + "images": { + "binding": "IMAGES" + } } diff --git a/packages/cloudflare/src/api/cloudflare-context.ts b/packages/cloudflare/src/api/cloudflare-context.ts index fbdc111fe..cfde3167b 100644 --- a/packages/cloudflare/src/api/cloudflare-context.ts +++ b/packages/cloudflare/src/api/cloudflare-context.ts @@ -13,6 +13,10 @@ declare global { // Asset binding ASSETS?: Fetcher; + // Images binding for image optimization + // Optimization is disabled if undefined + IMAGES?: ImagesBinding; + // Environment to use when loading Next `.env` files // Default to "production" NEXTJS_ENV?: string; diff --git a/packages/cloudflare/src/cli/build/open-next/compile-images.ts b/packages/cloudflare/src/cli/build/open-next/compile-images.ts index 6d4991fbb..4fb1c296b 100644 --- a/packages/cloudflare/src/cli/build/open-next/compile-images.ts +++ b/packages/cloudflare/src/cli/build/open-next/compile-images.ts @@ -19,7 +19,16 @@ export async function compileImages(options: BuildOptions) { : {}; const __IMAGES_REMOTE_PATTERNS__ = JSON.stringify(imagesManifest?.images?.remotePatterns ?? []); - const __IMAGES_LOCAL_PATTERNS__ = JSON.stringify(imagesManifest?.images?.localPatterns ?? []); + const __IMAGES_LOCAL_PATTERNS__ = JSON.stringify( + imagesManifest?.images?.localPatterns ?? defaultLocalPatterns + ); + const __IMAGES_DEVICE_SIZES__ = JSON.stringify(imagesManifest?.images?.deviceSizes ?? defaultDeviceSizes); + const __IMAGES_IMAGE_SIZES__ = JSON.stringify(imagesManifest?.images?.imageSizes ?? defaultImageSizes); + const __IMAGES_QUALITIES__ = JSON.stringify(imagesManifest?.images?.qualities ?? defaultQualities); + const __IMAGES_FORMATS__ = JSON.stringify(imagesManifest?.images?.formats ?? defaultFormats); + const __IMAGES_MINIMUM_CACHE_TTL_SEC__ = JSON.stringify( + imagesManifest?.images?.minimumCacheTTL ?? defaultMinimumCacheTTLSec + ); const __IMAGES_ALLOW_SVG__ = JSON.stringify(Boolean(imagesManifest?.images?.dangerouslyAllowSVG)); const __IMAGES_CONTENT_SECURITY_POLICY__ = JSON.stringify( imagesManifest?.images?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;" @@ -27,11 +36,14 @@ export async function compileImages(options: BuildOptions) { const __IMAGES_CONTENT_DISPOSITION__ = JSON.stringify( imagesManifest?.images?.contentDispositionType ?? "attachment" ); + const __IMAGES_MAX_REDIRECTS__ = JSON.stringify( + imagesManifest?.images?.maximumRedirects ?? defaultMaxRedirects + ); await build({ entryPoints: [imagesPath], outdir: path.join(options.outputDir, "cloudflare"), - bundle: false, + bundle: true, minify: false, format: "esm", target: "esnext", @@ -39,9 +51,32 @@ export async function compileImages(options: BuildOptions) { define: { __IMAGES_REMOTE_PATTERNS__, __IMAGES_LOCAL_PATTERNS__, + __IMAGES_DEVICE_SIZES__, + __IMAGES_IMAGE_SIZES__, + __IMAGES_QUALITIES__, + __IMAGES_FORMATS__, + __IMAGES_MINIMUM_CACHE_TTL_SEC__, __IMAGES_ALLOW_SVG__, __IMAGES_CONTENT_SECURITY_POLICY__, __IMAGES_CONTENT_DISPOSITION__, + __IMAGES_MAX_REDIRECTS__, }, }); } + +const defaultDeviceSizes = [640, 750, 828, 1080, 1200, 1920, 2048, 3840]; + +// 16 was included in Next.js 15 +const defaultImageSizes = [32, 48, 64, 96, 128, 256, 384]; + +// All values between 1-100 were allowed in Next.js 15 +const defaultQualities = [75]; + +// Was unlimited in Next.js 15 +const defaultMaxRedirects = 3; + +const defaultFormats = ["image/webp"]; + +const defaultMinimumCacheTTLSec = 14400; + +const defaultLocalPatterns = { pathname: "/**" }; diff --git a/packages/cloudflare/src/cli/templates/images.ts b/packages/cloudflare/src/cli/templates/images.ts index 3fa47f312..dbe6ef445 100644 --- a/packages/cloudflare/src/cli/templates/images.ts +++ b/packages/cloudflare/src/cli/templates/images.ts @@ -1,3 +1,5 @@ +import { error, warn } from "@opennextjs/aws/adapters/logger.js"; + export type RemotePattern = { protocol?: "http" | "https"; hostname: string; @@ -13,120 +15,581 @@ export type LocalPattern = { search?: string; }; -let NEXT_IMAGE_REGEXP: RegExp; - /** - * Fetches an images. + * Handles requests to /_next/image(/), including image optimizations. + * + * Image optimization is disabled and the original image is returned if `env.IMAGES` is undefined. * - * Local images (starting with a '/' as fetched using the passed fetcher). - * Remote images should match the configured remote patterns or a 404 response is returned. + * Throws an exception on unexpected errors. + * + * @param requestURL + * @param requestHeaders + * @param env + * @returns A promise that resolves to the resolved request. */ -export async function fetchImage(fetcher: Fetcher | undefined, imageUrl: string, ctx: ExecutionContext) { - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L208 - if (!imageUrl || imageUrl.length > 3072 || imageUrl.startsWith("//")) { - return getUrlErrorResponse(); +export async function handleImageRequest( + requestURL: URL, + requestHeaders: Headers, + env: CloudflareEnv +): Promise { + const parseResult = parseImageRequest(requestURL, requestHeaders); + if (!parseResult.ok) { + return new Response(parseResult.message, { + status: 400, + }); } - // Local - if (imageUrl.startsWith("/")) { - // @ts-expect-error TS2339 Missing types for URL.parse - const url = URL.parse(imageUrl, "http://n"); + let imageResponse: Response; + if (parseResult.url.startsWith("/")) { + if (env.ASSETS === undefined) { + error("env.ASSETS binding is not defined"); + return new Response('"url" parameter is valid but upstream response is invalid', { + status: 404, + }); + } + const absoluteURL = new URL(parseResult.url, requestURL); + imageResponse = await env.ASSETS.fetch(absoluteURL); + } else { + let fetchImageResult: FetchWithRedirectsResult; + try { + fetchImageResult = await fetchWithRedirects(parseResult.url, 7_000, __IMAGES_MAX_REDIRECTS__); + } catch (e) { + throw new Error("Failed to fetch image", { cause: e }); + } + if (!fetchImageResult.ok) { + if (fetchImageResult.error === "timed_out") { + return new Response('"url" parameter is valid but upstream response timed out', { + status: 504, + }); + } + if (fetchImageResult.error === "too_many_redirects") { + return new Response('"url" parameter is valid but upstream response is invalid', { + status: 508, + }); + } + throw new Error("Failed to fetch image"); + } + imageResponse = fetchImageResult.response; + } - if (url == null) { - return getUrlErrorResponse(); + if (!imageResponse.ok || imageResponse.body === null) { + return new Response('"url" parameter is valid but upstream response is invalid', { + status: imageResponse.status, + }); + } + + let immutable = false; + if (parseResult.static) { + immutable = true; + } else { + const cacheControlHeader = imageResponse.headers.get("Cache-Control"); + if (cacheControlHeader !== null) { + // TODO: Properly parse header + immutable = cacheControlHeader.includes("immutable"); } + } - // This method will never throw because URL parser will handle invalid input. - const pathname = decodeURIComponent(url.pathname); + const [contentTypeImageStream, imageStream] = imageResponse.body.tee(); + const imageHeaderBytes = new Uint8Array(32); + const contentTypeImageReader = contentTypeImageStream.getReader({ + mode: "byob", + }); + const readImageHeaderBytesResult = await contentTypeImageReader.readAtLeast(32, imageHeaderBytes); + if (readImageHeaderBytesResult.value === undefined) { + await imageResponse.body.cancel(); - NEXT_IMAGE_REGEXP ??= /\/_next\/image($|\/)/; - if (NEXT_IMAGE_REGEXP.test(pathname)) { - return getUrlErrorResponse(); + return new Response('"url" parameter is valid but upstream response is invalid', { + status: 400, + }); + } + const contentType = detectImageContentType(readImageHeaderBytesResult.value); + if (contentType === null) { + warn(`Failed to detect content type of "${parseResult.url}"`); + return new Response('"url" parameter is valid but image type is not allowed', { + status: 400, + }); + } + if (contentType === SVG) { + if (!__IMAGES_ALLOW_SVG__) { + return new Response('"url" parameter is valid but image type is not allowed', { + status: 400, + }); } + const response = createImageResponse(imageStream, contentType, { + immutable, + }); + return response; + } - // If localPatterns are not defined all local images are allowed. - if ( - __IMAGES_LOCAL_PATTERNS__.length > 0 && - !__IMAGES_LOCAL_PATTERNS__.some((p: LocalPattern) => matchLocalPattern(p, url)) - ) { - return getUrlErrorResponse(); + if (contentType === GIF) { + if (env.IMAGES === undefined) { + warn("env.IMAGES binding is not defined"); + const response = createImageResponse(imageStream, contentType, { + immutable, + }); + return response; } - return fetcher?.fetch(`http://assets.local${imageUrl}`); + const imageSource = env.IMAGES.input(imageStream); + const imageTransformationResult = await imageSource + .transform({ + width: parseResult.width, + fit: "scale-down", + }) + .output({ + quality: parseResult.quality, + format: GIF, + }); + const outputImageStream = imageTransformationResult.image(); + const response = createImageResponse(outputImageStream, GIF, { + immutable, + }); + return response; } - // Remote - let url: URL; - try { - url = new URL(imageUrl); - } catch { - return getUrlErrorResponse(); + if (contentType === AVIF || contentType === WEBP || contentType === JPEG || contentType === PNG) { + if (env.IMAGES === undefined) { + warn("env.IMAGES binding is not defined"); + const response = createImageResponse(imageStream, contentType, { + immutable, + }); + return response; + } + + const outputFormat = parseResult.format ?? contentType; + const imageSource = env.IMAGES.input(imageStream); + const imageTransformationResult = await imageSource + .transform({ + width: parseResult.width, + fit: "scale-down", + }) + .output({ + quality: parseResult.quality, + format: outputFormat, + }); + const outputImageStream = imageTransformationResult.image(); + const response = createImageResponse(outputImageStream, outputFormat, { + immutable, + }); + return response; } - if (url.protocol !== "http:" && url.protocol !== "https:") { - return getUrlErrorResponse(); + warn(`Image content type ${contentType} not supported`); + + const response = createImageResponse(imageStream, contentType, { + immutable, + }); + + return response; +} + +/** + * Fetch call with max redirects and timeouts. + * + * Re-throws the exception thrown by a fetch call. + * @param url + * @param timeoutMS Timeout for a single fetch call. + * @param maxRedirectCount + * @returns + */ +async function fetchWithRedirects( + url: string, + timeoutMS: number, + maxRedirectCount: number +): Promise { + // TODO: Add dangerouslyAllowLocalIP support + + let response: Response; + try { + response = await fetch(url, { + signal: AbortSignal.timeout(timeoutMS), + redirect: "manual", + }); + } catch (e) { + if (e instanceof Error && e.name === "TimeoutError") { + const result: FetchWithRedirectsErrorResult = { + ok: false, + error: "timed_out", + }; + return result; + } + throw e; + } + if (redirectResponseStatuses.includes(response.status)) { + const locationHeader = response.headers.get("Location"); + if (locationHeader !== null) { + if (maxRedirectCount < 1) { + const result: FetchWithRedirectsErrorResult = { + ok: false, + error: "too_many_redirects", + }; + return result; + } + let redirectTarget: string; + if (locationHeader.startsWith("/")) { + redirectTarget = new URL(locationHeader, url).href; + } else { + redirectTarget = locationHeader; + } + const result = await fetchWithRedirects(redirectTarget, timeoutMS, maxRedirectCount - 1); + return result; + } } + const result: FetchWithRedirectsSuccessResult = { + ok: true, + response: response, + }; + return result; +} + +type FetchWithRedirectsResult = FetchWithRedirectsSuccessResult | FetchWithRedirectsErrorResult; - // The remotePatterns is used to allow images from specific remote external paths and block all others. - if (!__IMAGES_REMOTE_PATTERNS__.some((p: RemotePattern) => matchRemotePattern(p, url))) { - return getUrlErrorResponse(); +type FetchWithRedirectsSuccessResult = { + ok: true; + response: Response; +}; + +type FetchWithRedirectsErrorResult = { + ok: false; + error: FetchImageError; +}; + +type FetchImageError = "timed_out" | "too_many_redirects"; + +const redirectResponseStatuses = [301, 302, 303, 307, 308]; + +function createImageResponse( + image: ReadableStream, + contentType: string, + imageResponseFlags: ImageResponseFlags +): Response { + const response = new Response(image, { + headers: { + Vary: "Accept", + "Content-Type": contentType, + "Content-Disposition": __IMAGES_CONTENT_DISPOSITION__, + "Content-Security-Policy": __IMAGES_CONTENT_SECURITY_POLICY__, + }, + }); + if (imageResponseFlags.immutable) { + response.headers.set("Cache-Control", "public, max-age=315360000, immutable"); } + return response; +} - const imgResponse = await fetch(imageUrl, { cf: { cacheEverything: true } }); +type ImageResponseFlags = { + immutable: boolean; +}; - if (!imgResponse.body) { - return imgResponse; +/** + * Parses the image request URL and headers. + * + * This function validates the parameters and returns either the parsed result or an error message. + * + * @param requestURL request URL + * @param requestHeaders request headers + * @returns an instance of `ParseImageRequestURLSuccessResult` when successful, or an instance of `ErrorResult` when failed. + */ +function parseImageRequest( + requestURL: URL, + requestHeaders: Headers +): ParseImageRequestURLSuccessResult | ErrorResult { + const formats = __IMAGES_FORMATS__; + + const parsedUrlOrError = validateUrlQueryParameter(requestURL); + if (!("url" in parsedUrlOrError)) { + return parsedUrlOrError; } - const buffer = new ArrayBuffer(32); + const widthOrError = validateWidthQueryParameter(requestURL); + if (typeof widthOrError !== "number") { + return widthOrError; + } - try { - let contentType: string | undefined; - // respBody is eventually used for the response - // contentBody is used to detect the content type - const [respBody, contentBody] = imgResponse.body.tee(); - const reader = contentBody.getReader({ mode: "byob" }); - const { value } = await reader.read(new Uint8Array(buffer)); - // Release resources by calling `reader.cancel()` - // `ctx.waitUntil` keeps the runtime running until the promise settles without having to wait here. - ctx.waitUntil(reader.cancel()); - - if (value) { - contentType = detectContentType(value); - } + const qualityOrError = validateQualityQueryParameter(requestURL); + if (typeof qualityOrError !== "number") { + return qualityOrError; + } - if (!contentType) { - // Fallback to upstream header when the type can not be detected - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L748 - contentType = imgResponse.headers.get("content-type") ?? ""; + const acceptHeader = requestHeaders.get("Accept") ?? ""; + let format: OptimizedImageFormat | null = null; + // Find a more specific format that the client accepts. + for (const allowedFormat of formats) { + if (acceptHeader.includes(allowedFormat)) { + format = allowedFormat; + break; } + } + + const result: ParseImageRequestURLSuccessResult = { + ok: true, + url: parsedUrlOrError.url, + width: widthOrError, + quality: qualityOrError, + format, + static: parsedUrlOrError.static, + }; + return result; +} + +type ParseImageRequestURLSuccessResult = { + ok: true; + /** Absolute or relative URL. */ + url: string; + width: number; + quality: number; + format: OptimizedImageFormat | null; + static: boolean; +}; + +export type OptimizedImageFormat = "image/avif" | "image/webp"; + +type ErrorResult = { + ok: false; + message: string; +}; - // Sanitize the content type: - // - Accept images only - // - Reject multiple content types - if (!contentType.startsWith("image/") || contentType.includes(",")) { - contentType = undefined; +/** + * Validates that there is exactly one "url" query parameter. + * + * @returns the validated URL or an error result. + */ +function validateUrlQueryParameter(requestURL: URL): ErrorResult | { url: string; static: boolean } { + // There should be a single "url" parameter. + const urls = requestURL.searchParams.getAll("url"); + if (urls.length < 1) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter is required', + }; + return result; + } + if (urls.length > 1) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter cannot be an array', + }; + return result; + } + + // The url parameter value should be a valid URL or a valid relative URL. + const url = urls[0]!; + if (url.length > 3072) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter is too long', + }; + return result; + } + if (url.startsWith("//")) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter cannot be a protocol-relative URL (//)', + }; + return result; + } + + if (url.startsWith("/")) { + const staticAsset = url.startsWith(`${__NEXT_BASE_PATH__ || ""}/_next/static/media`); + + const pathname = getPathnameFromRelativeURL(url); + if (/\/_next\/image($|\/)/.test(decodeURIComponent(pathname))) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter cannot be recursive', + }; + return result; } - if (contentType && !(contentType === SVG && !__IMAGES_ALLOW_SVG__)) { - const headers = new Headers(imgResponse.headers); - headers.set("content-type", contentType); - headers.set("content-disposition", __IMAGES_CONTENT_DISPOSITION__); - headers.set("content-security-policy", __IMAGES_CONTENT_SECURITY_POLICY__); - return new Response(respBody, { ...imgResponse, headers }); + if (!staticAsset) { + if (!hasLocalMatch(__IMAGES_LOCAL_PATTERNS__, url)) { + const result: ErrorResult = { ok: false, message: '"url" parameter is not allowed' }; + return result; + } } - // Cancel the unused stream - ctx.waitUntil(respBody.cancel()); + return { url, static: staticAsset }; + } - return new Response('"url" parameter is valid but image type is not allowed', { - status: 400, - }); + let parsedURL: URL; + try { + parsedURL = new URL(url); } catch { - return new Response('"url" parameter is valid but upstream response is invalid', { - status: 400, - }); + const result: ErrorResult = { ok: false, message: '"url" parameter is invalid' }; + return result; + } + + const validProtocols = ["http:", "https:"]; + if (!validProtocols.includes(parsedURL.protocol)) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter is invalid', + }; + return result; + } + if (!hasRemoteMatch(__IMAGES_REMOTE_PATTERNS__, parsedURL)) { + const result: ErrorResult = { + ok: false, + message: '"url" parameter is not allowed', + }; + return result; + } + + return { url: parsedURL.href, static: false }; +} + +/** + * Validates the "w" (width) query parameter. + * + * @returns the validated width number or an error result. + */ +function validateWidthQueryParameter(requestURL: URL): ErrorResult | number { + const widthQueryValues = requestURL.searchParams.getAll("w"); + if (widthQueryValues.length < 1) { + const result: ErrorResult = { + ok: false, + message: '"w" parameter (width) is required', + }; + return result; + } + if (widthQueryValues.length > 1) { + const result: ErrorResult = { + ok: false, + message: '"w" parameter (width) cannot be an array', + }; + return result; + } + const widthQueryValue = widthQueryValues[0]!; + if (!/^[0-9]+$/.test(widthQueryValue)) { + const result: ErrorResult = { + ok: false, + message: '"w" parameter (width) must be an integer greater than 0', + }; + return result; + } + const width = parseInt(widthQueryValue, 10); + if (width <= 0 || isNaN(width)) { + const result: ErrorResult = { + ok: false, + message: '"w" parameter (width) must be an integer greater than 0', + }; + return result; + } + + const sizeValid = __IMAGES_DEVICE_SIZES__.includes(width) || __IMAGES_IMAGE_SIZES__.includes(width); + if (!sizeValid) { + const result: ErrorResult = { + ok: false, + message: `"w" parameter (width) of ${width} is not allowed`, + }; + return result; + } + + return width; +} + +/** + * Validates the "q" (quality) query parameter. + * + * @returns the validated quality number or an error result. + */ +function validateQualityQueryParameter(requestURL: URL): ErrorResult | number { + const qualityQueryValues = requestURL.searchParams.getAll("q"); + if (qualityQueryValues.length < 1) { + const result: ErrorResult = { + ok: false, + message: '"q" parameter (quality) is required', + }; + return result; + } + if (qualityQueryValues.length > 1) { + const result: ErrorResult = { + ok: false, + message: '"q" parameter (quality) cannot be an array', + }; + return result; + } + const qualityQueryValue = qualityQueryValues[0]!; + if (!/^[0-9]+$/.test(qualityQueryValue)) { + const result: ErrorResult = { + ok: false, + message: '"q" parameter (quality) must be an integer between 1 and 100', + }; + return result; + } + const quality = parseInt(qualityQueryValue, 10); + if (isNaN(quality) || quality < 1 || quality > 100) { + const result: ErrorResult = { + ok: false, + message: '"q" parameter (quality) must be an integer between 1 and 100', + }; + return result; + } + if (!__IMAGES_QUALITIES__.includes(quality)) { + const result: ErrorResult = { + ok: false, + message: `"q" parameter (quality) of ${quality} is not allowed`, + }; + return result; + } + + return quality; +} + +function getPathnameFromRelativeURL(relativeURL: string): string { + return relativeURL.split("?")[0]!; +} + +function hasLocalMatch(localPatterns: LocalPattern[], relativeURL: string): boolean { + const parseRelativeURLResult = parseRelativeURL(relativeURL); + for (const localPattern of localPatterns) { + const matched = matchLocalPattern(localPattern, parseRelativeURLResult); + if (matched) { + return true; + } } + return false; +} + +function parseRelativeURL(relativeURL: string): ParseRelativeURLResult { + if (!relativeURL.includes("?")) { + const result: ParseRelativeURLResult = { + pathname: relativeURL, + search: "", + }; + return result; + } + const parts = relativeURL.split("?"); + const pathname = parts[0]!; + const search = "?" + parts.slice(1).join("?"); + const result: ParseRelativeURLResult = { + pathname, + search, + }; + return result; +} + +type ParseRelativeURLResult = { + pathname: string; + search: string; +}; + +export function matchLocalPattern(pattern: LocalPattern, url: { pathname: string; search: string }): boolean { + if (pattern.search !== undefined && pattern.search !== url.search) { + return false; + } + + return new RegExp(pattern.pathname).test(url.pathname); +} + +function hasRemoteMatch(remotePatterns: RemotePattern[], url: URL): boolean { + for (const remotePattern of remotePatterns) { + const matched = matchRemotePattern(remotePattern, url); + if (matched) { + return true; + } + } + return false; } export function matchRemotePattern(pattern: RemotePattern, url: URL): boolean { @@ -154,22 +617,6 @@ export function matchRemotePattern(pattern: RemotePattern, url: URL): boolean { return new RegExp(pattern.pathname).test(url.pathname); } -export function matchLocalPattern(pattern: LocalPattern, url: URL): boolean { - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/shared/lib/match-local-pattern.ts - if (pattern.search !== undefined && pattern.search !== url.search) { - return false; - } - - return new RegExp(pattern.pathname).test(url.pathname); -} - -/** - * @returns same error as Next.js when the url query parameter is not accepted. - */ -function getUrlErrorResponse() { - return new Response(`"url" parameter is not allowed`, { status: 400 }); -} - const AVIF = "image/avif"; const WEBP = "image/webp"; const PNG = "image/png"; @@ -183,8 +630,21 @@ const ICO = "image/x-icon"; const ICNS = "image/x-icns"; const TIFF = "image/tiff"; const BMP = "image/bmp"; -// pdf will be rejected (not an `image/...` type) -const PDF = "application/pdf"; + +type ImageContentType = + | "image/avif" + | "image/webp" + | "image/png" + | "image/jpeg" + | "image/jxl" + | "image/jp2" + | "image/heic" + | "image/gif" + | "image/svg+xml" + | "image/x-icon" + | "image/x-icns" + | "image/tiff" + | "image/bmp"; /** * Detects the content type by looking at the first few bytes of a file @@ -194,7 +654,7 @@ const PDF = "application/pdf"; * @param buffer The image bytes * @returns a content type of undefined for unsupported content */ -export function detectContentType(buffer: Uint8Array) { +export function detectImageContentType(buffer: Uint8Array): ImageContentType | null { if ([0xff, 0xd8, 0xff].every((b, i) => buffer[i] === b)) { return JPEG; } @@ -239,20 +699,26 @@ export function detectContentType(buffer: Uint8Array) { if ([0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63].every((b, i) => !b || buffer[i] === b)) { return HEIC; } - if ([0x25, 0x50, 0x44, 0x46, 0x2d].every((b, i) => buffer[i] === b)) { - return PDF; - } if ( [0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b) ) { return JP2; } + return null; } declare global { var __IMAGES_REMOTE_PATTERNS__: RemotePattern[]; var __IMAGES_LOCAL_PATTERNS__: LocalPattern[]; + var __IMAGES_DEVICE_SIZES__: number[]; + var __IMAGES_IMAGE_SIZES__: number[]; + var __IMAGES_QUALITIES__: number[]; + var __IMAGES_FORMATS__: NextConfigImageFormat[]; + var __IMAGES_MINIMUM_CACHE_TTL_SEC__: number; var __IMAGES_ALLOW_SVG__: boolean; var __IMAGES_CONTENT_SECURITY_POLICY__: string; var __IMAGES_CONTENT_DISPOSITION__: string; + var __IMAGES_MAX_REDIRECTS__: number; + + type NextConfigImageFormat = "image/avif" | "image/webp"; } diff --git a/packages/cloudflare/src/cli/templates/worker.ts b/packages/cloudflare/src/cli/templates/worker.ts index 6d2c3fdf0..95dded9ca 100644 --- a/packages/cloudflare/src/cli/templates/worker.ts +++ b/packages/cloudflare/src/cli/templates/worker.ts @@ -1,12 +1,11 @@ //@ts-expect-error: Will be resolved by wrangler build -import { fetchImage } from "./cloudflare/images.js"; +import { handleImageRequest } from "./cloudflare/images.js"; //@ts-expect-error: Will be resolved by wrangler build import { runWithCloudflareRequestContext } from "./cloudflare/init.js"; //@ts-expect-error: Will be resolved by wrangler build import { maybeGetSkewProtectionResponse } from "./cloudflare/skew-protection.js"; // @ts-expect-error: Will be resolved by wrangler build import { handler as middlewareHandler } from "./middleware/handler.mjs"; - //@ts-expect-error: Will be resolved by wrangler build export { DOQueueHandler } from "./.build/durable-objects/queue.js"; //@ts-expect-error: Will be resolved by wrangler build @@ -43,8 +42,7 @@ export default { url.pathname === `${globalThis.__NEXT_BASE_PATH__}/_next/image${globalThis.__TRAILING_SLASH__ ? "/" : ""}` ) { - const imageUrl = url.searchParams.get("url") ?? ""; - return await fetchImage(env.ASSETS, imageUrl, ctx); + return await handleImageRequest(url, request.headers, env); } // - `Request`s are handled by the Next server diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ccf529033..037e60bf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -911,6 +911,9 @@ importers: '@types/node': specifier: 'catalog:' version: 22.2.0 + sharp: + specifier: ^0.34.5 + version: 0.34.5 wrangler: specifier: 'catalog:' version: 4.49.1(@cloudflare/workers-types@4.20250924.0) @@ -1854,12 +1857,12 @@ packages: resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} engines: {node: '>=16'} - '@emnapi/runtime@1.4.3': - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} - '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -3119,6 +3122,10 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3131,6 +3138,12 @@ packages: cpu: [arm64] os: [darwin] + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3143,6 +3156,12 @@ packages: cpu: [x64] os: [darwin] + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + 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==} cpu: [arm64] @@ -3153,6 +3172,11 @@ packages: cpu: [arm64] os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + '@img/sharp-libvips-darwin-x64@1.0.4': resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} cpu: [x64] @@ -3163,6 +3187,11 @@ packages: cpu: [x64] os: [darwin] + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-linux-arm64@1.0.4': resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] @@ -3173,6 +3202,11 @@ packages: cpu: [arm64] os: [linux] + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] @@ -3183,11 +3217,26 @@ packages: cpu: [arm] os: [linux] + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + '@img/sharp-libvips-linux-ppc64@1.2.0': resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} cpu: [ppc64] os: [linux] + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] @@ -3198,6 +3247,11 @@ packages: cpu: [s390x] os: [linux] + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] @@ -3208,6 +3262,11 @@ packages: cpu: [x64] os: [linux] + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] @@ -3218,6 +3277,11 @@ packages: cpu: [arm64] os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] @@ -3228,6 +3292,11 @@ packages: cpu: [x64] os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3240,6 +3309,12 @@ packages: cpu: [arm64] os: [linux] + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3252,12 +3327,30 @@ packages: cpu: [arm] os: [linux] + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + '@img/sharp-linux-ppc64@0.34.3': resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3270,6 +3363,12 @@ packages: cpu: [s390x] os: [linux] + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3282,6 +3381,12 @@ packages: cpu: [x64] os: [linux] + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3294,6 +3399,12 @@ packages: cpu: [arm64] os: [linux] + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3306,6 +3417,12 @@ packages: cpu: [x64] os: [linux] + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3316,12 +3433,23 @@ packages: engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + '@img/sharp-win32-arm64@0.34.3': resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + '@img/sharp-win32-ia32@0.33.5': resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3334,6 +3462,12 @@ packages: cpu: [ia32] os: [win32] + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + 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==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3346,6 +3480,12 @@ packages: cpu: [x64] os: [win32] + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -5888,14 +6028,14 @@ packages: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -6417,16 +6557,6 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.30.0: - resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint-plugin-import@2.31.0: resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} @@ -8935,6 +9065,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -8972,6 +9107,10 @@ packages: resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -11633,12 +11772,12 @@ snapshots: dependencies: '@edge-runtime/primitives': 4.1.0 - '@emnapi/runtime@1.4.3': + '@emnapi/runtime@1.4.5': dependencies: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.5': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -12655,6 +12794,8 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.0.0': {} + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -12665,6 +12806,11 @@ snapshots: '@img/sharp-libvips-darwin-arm64': 1.2.0 optional: true + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + '@img/sharp-darwin-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.0.4 @@ -12675,57 +12821,92 @@ snapshots: '@img/sharp-libvips-darwin-x64': 1.2.0 optional: true + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true '@img/sharp-libvips-darwin-arm64@1.2.0': optional: true + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true '@img/sharp-libvips-darwin-x64@1.2.0': optional: true + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true '@img/sharp-libvips-linux-arm64@1.2.0': optional: true + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + '@img/sharp-libvips-linux-arm@1.0.5': optional: true '@img/sharp-libvips-linux-arm@1.2.0': optional: true + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + '@img/sharp-libvips-linux-ppc64@1.2.0': optional: true + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true '@img/sharp-libvips-linux-s390x@1.2.0': optional: true + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + '@img/sharp-libvips-linux-x64@1.0.4': optional: true '@img/sharp-libvips-linux-x64@1.2.0': optional: true + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true '@img/sharp-libvips-linuxmusl-arm64@1.2.0': optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true '@img/sharp-libvips-linuxmusl-x64@1.2.0': optional: true + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.4 @@ -12736,6 +12917,11 @@ snapshots: '@img/sharp-libvips-linux-arm64': 1.2.0 optional: true + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + '@img/sharp-linux-arm@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.0.5 @@ -12746,11 +12932,26 @@ snapshots: '@img/sharp-libvips-linux-arm': 1.2.0 optional: true + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + '@img/sharp-linux-ppc64@0.34.3': optionalDependencies: '@img/sharp-libvips-linux-ppc64': 1.2.0 optional: true + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.0.4 @@ -12761,6 +12962,11 @@ snapshots: '@img/sharp-libvips-linux-s390x': 1.2.0 optional: true + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + '@img/sharp-linux-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.0.4 @@ -12771,6 +12977,11 @@ snapshots: '@img/sharp-libvips-linux-x64': 1.2.0 optional: true + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 @@ -12781,6 +12992,11 @@ snapshots: '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 optional: true + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.0.4 @@ -12791,9 +13007,14 @@ snapshots: '@img/sharp-libvips-linuxmusl-x64': 1.2.0 optional: true + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.4.3 + '@emnapi/runtime': 1.4.5 optional: true '@img/sharp-wasm32@0.34.3': @@ -12801,21 +13022,35 @@ snapshots: '@emnapi/runtime': 1.4.5 optional: true + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 + optional: true + '@img/sharp-win32-arm64@0.34.3': optional: true + '@img/sharp-win32-arm64@0.34.5': + optional: true + '@img/sharp-win32-ia32@0.33.5': optional: true '@img/sharp-win32-ia32@0.34.3': optional: true + '@img/sharp-win32-ia32@0.34.5': + optional: true + '@img/sharp-win32-x64@0.33.5': optional: true '@img/sharp-win32-x64@0.34.3': optional: true + '@img/sharp-win32-x64@0.34.5': + optional: true + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': @@ -12957,7 +13192,7 @@ snapshots: https-proxy-agent: 7.0.6 node-fetch: 2.7.0 nopt: 8.1.0 - semver: 7.7.1 + semver: 7.7.2 tar: 7.4.3 transitivePeerDependencies: - encoding @@ -14889,7 +15124,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -14903,7 +15138,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 ts-api-utils: 1.4.3(typescript@5.7.3) optionalDependencies: typescript: 5.7.3 @@ -14918,7 +15153,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 ts-api-utils: 1.4.3(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -15848,10 +16083,10 @@ snapshots: detect-libc@2.0.2: {} - detect-libc@2.0.3: {} - detect-libc@2.0.4: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -16402,8 +16637,8 @@ snapshots: '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.36.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) @@ -16422,7 +16657,7 @@ snapshots: '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.36.1(eslint@8.57.1) @@ -16442,7 +16677,7 @@ snapshots: '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) eslint: 9.11.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.11.1(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)) eslint-plugin-jsx-a11y: 6.10.0(eslint@9.11.1(jiti@1.21.6)) eslint-plugin-react: 7.37.4(eslint@9.11.1(jiti@1.21.6)) @@ -16462,7 +16697,7 @@ snapshots: '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) eslint: 9.19.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.19.0(jiti@1.21.6)) eslint-plugin-jsx-a11y: 6.10.0(eslint@9.19.0(jiti@1.21.6)) eslint-plugin-react: 7.37.4(eslint@9.19.0(jiti@1.21.6)) @@ -16482,13 +16717,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.2.1 @@ -16501,32 +16736,32 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.11.1(jiti@1.21.6)): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 9.11.1(jiti@1.21.6) - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)) + eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.2.1 @@ -16539,13 +16774,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@1.21.6)): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 enhanced-resolve: 5.17.1 eslint: 9.19.0(jiti@1.21.6) - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.19.0(jiti@1.21.6)) + eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)) fast-glob: 3.3.2 get-tsconfig: 4.8.0 is-bun-module: 1.2.1 @@ -16558,47 +16793,47 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)): + eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) eslint: 9.11.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.11.1(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.19.0(jiti@1.21.6)): + eslint-module-utils@2.11.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) eslint: 9.19.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)) transitivePeerDependencies: - supports-color @@ -16612,40 +16847,51 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) + eslint: 8.57.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) eslint: 9.11.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.11.1(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.19.0(jiti@1.21.6)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) eslint: 9.19.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3))(eslint@9.31.0(jiti@1.21.6)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -16654,9 +16900,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 9.31.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16665,15 +16911,16 @@ snapshots: object.groupby: 1.0.3 object.values: 1.2.1 semver: 6.3.1 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3))(eslint@9.31.0(jiti@1.21.6)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -16682,9 +16929,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.31.0(jiti@1.21.6) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.31.0(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16696,13 +16943,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.37.0(eslint@9.31.0(jiti@1.21.6))(typescript@5.9.3) + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -16713,7 +16960,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16725,7 +16972,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16742,7 +16989,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.11.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)))(eslint@9.11.1(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16771,7 +17018,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.19.0(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.19.0(jiti@1.21.6)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)))(eslint@9.19.0(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -17967,7 +18214,7 @@ snapshots: is-bun-module@1.2.1: dependencies: - semver: 7.7.1 + semver: 7.7.2 is-callable@1.2.7: {} @@ -18210,7 +18457,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.7.1 + semver: 7.7.2 jsx-ast-utils@3.3.5: dependencies: @@ -19031,7 +19278,7 @@ snapshots: node-abi@3.73.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 node-domexception@1.0.0: {} @@ -19519,7 +19766,7 @@ snapshots: prebuild-install@7.1.3: dependencies: - detect-libc: 2.0.3 + detect-libc: 2.0.4 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 @@ -19980,8 +20227,9 @@ snapshots: semver@7.7.1: {} - semver@7.7.2: - optional: true + semver@7.7.2: {} + + semver@7.7.3: {} send@1.2.0: dependencies: @@ -20040,7 +20288,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.0.4 - semver: 7.7.1 + semver: 7.7.2 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5 @@ -20092,6 +20340,37 @@ snapshots: '@img/sharp-win32-x64': 0.34.3 optional: true + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0