this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add image optimization with Cloudflare Images (#999)

Co-authored-by: Hinata Masaki <hinata@cloudflare.com>
Co-authored-by: Victor Berchet <victor@suumit.com>

authored by

pilcrow
Hinata Masaki
Victor Berchet
and committed by
GitHub
50d74273 b53a046b

+1026 -205
+34 -5
examples/playground14/e2e/cloudflare.spec.ts
··· 5 5 */ 6 6 7 7 import { test, expect } from "@playwright/test"; 8 + import sharp from "sharp"; 8 9 9 10 test.describe("playground/cloudflare", () => { 10 11 test("NextConfig", async ({ page }) => { ··· 21 22 22 23 test.describe("remotePatterns", () => { 23 24 test("fetch an image allowed by remotePatterns", async ({ page }) => { 24 - const res = await page.request.get("/_next/image?url=https://avatars.githubusercontent.com/u/248818"); 25 + const res = await page.request.get( 26 + "/_next/image?url=https://avatars.githubusercontent.com/u/248818&w=256&q=75" 27 + ); 25 28 expect(res.status()).toBe(200); 26 29 expect(res.headers()).toMatchObject({ "content-type": "image/jpeg" }); 27 30 }); 28 31 29 32 test("400 when fetching an image disallowed by remotePatterns", async ({ page }) => { 30 - const res = await page.request.get("/_next/image?url=https://avatars.githubusercontent.com/u/248817"); 33 + const res = await page.request.get( 34 + "/_next/image?url=https://avatars.githubusercontent.com/u/248817&w=256&q=75" 35 + ); 31 36 expect(res.status()).toBe(400); 32 37 }); 33 38 }); 34 39 35 40 test.describe("localPatterns", () => { 36 41 test("fetch an image allowed by localPatterns", async ({ page }) => { 37 - const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes"); 42 + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=75"); 38 43 expect(res.status()).toBe(200); 39 44 expect(res.headers()).toMatchObject({ "content-type": "image/webp" }); 40 45 }); ··· 42 47 test("400 when fetching an image disallowed by localPatterns with wrong query parameter", async ({ 43 48 page, 44 49 }) => { 45 - const res = await page.request.get("/_next/image?url=/snipp/snipp?iscute=no"); 50 + const res = await page.request.get("/_next/image?url=/snipp/snipp?iscute=no&w=256&q=75"); 46 51 expect(res.status()).toBe(400); 47 52 }); 48 53 49 54 test("400 when fetching an image disallowed by localPatterns without query parameter", async ({ 50 55 page, 51 56 }) => { 52 - const res = await page.request.get("/_next/image?url=/snipp/snipp"); 57 + const res = await page.request.get("/_next/image?url=/snipp/snipp&w=256&q=75"); 58 + expect(res.status()).toBe(400); 59 + }); 60 + }); 61 + 62 + test.describe("imageSizes", () => { 63 + test("400 when fetching an image with unsupported width value", async ({ page }) => { 64 + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=100&q=75"); 53 65 expect(res.status()).toBe(400); 66 + }); 67 + }); 68 + 69 + test.describe("qualities", () => { 70 + test("400 when fetching an image with unsupported quality value", async ({ page }) => { 71 + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=100"); 72 + expect(res.status()).toBe(400); 73 + }); 74 + }); 75 + 76 + test.describe('"w" parameter', () => { 77 + test("Image is shrunk to target width", async ({ page }) => { 78 + const res = await page.request.get("/_next/image?url=/snipp/snipp.webp?iscute=yes&w=256&q=75"); 79 + expect(res.status()).toBe(200); 80 + const buffer = await res.body(); 81 + const metadata = await sharp(buffer).metadata(); 82 + expect(metadata.width).toBe(256); 54 83 }); 55 84 }); 56 85 });
+1
examples/playground14/package.json
··· 24 24 "@opennextjs/cloudflare": "workspace:*", 25 25 "@playwright/test": "catalog:", 26 26 "@types/node": "catalog:", 27 + "sharp": "^0.34.5", 27 28 "wrangler": "catalog:" 28 29 } 29 30 }
+3
examples/playground14/wrangler.jsonc
··· 18 18 "hello": "Hello World from the cloudflare context!", 19 19 "PROCESS_ENV_VAR": "process.env", 20 20 "NEXT_INC_CACHE_KV_PREFIX": "custom_prefix" 21 + }, 22 + "images": { 23 + "binding": "IMAGES" 21 24 } 22 25 }
+3
examples/playground15/next.config.ts
··· 12 12 }, 13 13 deploymentId: getDeploymentId(), 14 14 trailingSlash: true, 15 + images: { 16 + formats: ["image/avif", "image/webp"], 17 + }, 15 18 }; 16 19 17 20 export default nextConfig;
+4 -1
examples/playground15/wrangler.jsonc
··· 44 44 "database_id": "db_id", 45 45 "database_name": "db_name" 46 46 } 47 - ] 47 + ], 48 + "images": { 49 + "binding": "IMAGES" 50 + } 48 51 }
+4
packages/cloudflare/src/api/cloudflare-context.ts
··· 13 13 // Asset binding 14 14 ASSETS?: Fetcher; 15 15 16 + // Images binding for image optimization 17 + // Optimization is disabled if undefined 18 + IMAGES?: ImagesBinding; 19 + 16 20 // Environment to use when loading Next `.env` files 17 21 // Default to "production" 18 22 NEXTJS_ENV?: string;
+37 -2
packages/cloudflare/src/cli/build/open-next/compile-images.ts
··· 19 19 : {}; 20 20 21 21 const __IMAGES_REMOTE_PATTERNS__ = JSON.stringify(imagesManifest?.images?.remotePatterns ?? []); 22 - const __IMAGES_LOCAL_PATTERNS__ = JSON.stringify(imagesManifest?.images?.localPatterns ?? []); 22 + const __IMAGES_LOCAL_PATTERNS__ = JSON.stringify( 23 + imagesManifest?.images?.localPatterns ?? defaultLocalPatterns 24 + ); 25 + const __IMAGES_DEVICE_SIZES__ = JSON.stringify(imagesManifest?.images?.deviceSizes ?? defaultDeviceSizes); 26 + const __IMAGES_IMAGE_SIZES__ = JSON.stringify(imagesManifest?.images?.imageSizes ?? defaultImageSizes); 27 + const __IMAGES_QUALITIES__ = JSON.stringify(imagesManifest?.images?.qualities ?? defaultQualities); 28 + const __IMAGES_FORMATS__ = JSON.stringify(imagesManifest?.images?.formats ?? defaultFormats); 29 + const __IMAGES_MINIMUM_CACHE_TTL_SEC__ = JSON.stringify( 30 + imagesManifest?.images?.minimumCacheTTL ?? defaultMinimumCacheTTLSec 31 + ); 23 32 const __IMAGES_ALLOW_SVG__ = JSON.stringify(Boolean(imagesManifest?.images?.dangerouslyAllowSVG)); 24 33 const __IMAGES_CONTENT_SECURITY_POLICY__ = JSON.stringify( 25 34 imagesManifest?.images?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;" ··· 27 36 const __IMAGES_CONTENT_DISPOSITION__ = JSON.stringify( 28 37 imagesManifest?.images?.contentDispositionType ?? "attachment" 29 38 ); 39 + const __IMAGES_MAX_REDIRECTS__ = JSON.stringify( 40 + imagesManifest?.images?.maximumRedirects ?? defaultMaxRedirects 41 + ); 30 42 31 43 await build({ 32 44 entryPoints: [imagesPath], 33 45 outdir: path.join(options.outputDir, "cloudflare"), 34 - bundle: false, 46 + bundle: true, 35 47 minify: false, 36 48 format: "esm", 37 49 target: "esnext", ··· 39 51 define: { 40 52 __IMAGES_REMOTE_PATTERNS__, 41 53 __IMAGES_LOCAL_PATTERNS__, 54 + __IMAGES_DEVICE_SIZES__, 55 + __IMAGES_IMAGE_SIZES__, 56 + __IMAGES_QUALITIES__, 57 + __IMAGES_FORMATS__, 58 + __IMAGES_MINIMUM_CACHE_TTL_SEC__, 42 59 __IMAGES_ALLOW_SVG__, 43 60 __IMAGES_CONTENT_SECURITY_POLICY__, 44 61 __IMAGES_CONTENT_DISPOSITION__, 62 + __IMAGES_MAX_REDIRECTS__, 45 63 }, 46 64 }); 47 65 } 66 + 67 + const defaultDeviceSizes = [640, 750, 828, 1080, 1200, 1920, 2048, 3840]; 68 + 69 + // 16 was included in Next.js 15 70 + const defaultImageSizes = [32, 48, 64, 96, 128, 256, 384]; 71 + 72 + // All values between 1-100 were allowed in Next.js 15 73 + const defaultQualities = [75]; 74 + 75 + // Was unlimited in Next.js 15 76 + const defaultMaxRedirects = 3; 77 + 78 + const defaultFormats = ["image/webp"]; 79 + 80 + const defaultMinimumCacheTTLSec = 14400; 81 + 82 + const defaultLocalPatterns = { pathname: "/**" };
+566 -100
packages/cloudflare/src/cli/templates/images.ts
··· 1 + import { error, warn } from "@opennextjs/aws/adapters/logger.js"; 2 + 1 3 export type RemotePattern = { 2 4 protocol?: "http" | "https"; 3 5 hostname: string; ··· 13 15 search?: string; 14 16 }; 15 17 16 - let NEXT_IMAGE_REGEXP: RegExp; 17 - 18 18 /** 19 - * Fetches an images. 19 + * Handles requests to /_next/image(/), including image optimizations. 20 20 * 21 - * Local images (starting with a '/' as fetched using the passed fetcher). 22 - * Remote images should match the configured remote patterns or a 404 response is returned. 21 + * Image optimization is disabled and the original image is returned if `env.IMAGES` is undefined. 22 + * 23 + * Throws an exception on unexpected errors. 24 + * 25 + * @param requestURL 26 + * @param requestHeaders 27 + * @param env 28 + * @returns A promise that resolves to the resolved request. 23 29 */ 24 - export async function fetchImage(fetcher: Fetcher | undefined, imageUrl: string, ctx: ExecutionContext) { 25 - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L208 26 - if (!imageUrl || imageUrl.length > 3072 || imageUrl.startsWith("//")) { 27 - return getUrlErrorResponse(); 30 + export async function handleImageRequest( 31 + requestURL: URL, 32 + requestHeaders: Headers, 33 + env: CloudflareEnv 34 + ): Promise<Response> { 35 + const parseResult = parseImageRequest(requestURL, requestHeaders); 36 + if (!parseResult.ok) { 37 + return new Response(parseResult.message, { 38 + status: 400, 39 + }); 28 40 } 29 41 30 - // Local 31 - if (imageUrl.startsWith("/")) { 32 - // @ts-expect-error TS2339 Missing types for URL.parse 33 - const url = URL.parse(imageUrl, "http://n"); 42 + let imageResponse: Response; 43 + if (parseResult.url.startsWith("/")) { 44 + if (env.ASSETS === undefined) { 45 + error("env.ASSETS binding is not defined"); 46 + return new Response('"url" parameter is valid but upstream response is invalid', { 47 + status: 404, 48 + }); 49 + } 50 + const absoluteURL = new URL(parseResult.url, requestURL); 51 + imageResponse = await env.ASSETS.fetch(absoluteURL); 52 + } else { 53 + let fetchImageResult: FetchWithRedirectsResult; 54 + try { 55 + fetchImageResult = await fetchWithRedirects(parseResult.url, 7_000, __IMAGES_MAX_REDIRECTS__); 56 + } catch (e) { 57 + throw new Error("Failed to fetch image", { cause: e }); 58 + } 59 + if (!fetchImageResult.ok) { 60 + if (fetchImageResult.error === "timed_out") { 61 + return new Response('"url" parameter is valid but upstream response timed out', { 62 + status: 504, 63 + }); 64 + } 65 + if (fetchImageResult.error === "too_many_redirects") { 66 + return new Response('"url" parameter is valid but upstream response is invalid', { 67 + status: 508, 68 + }); 69 + } 70 + throw new Error("Failed to fetch image"); 71 + } 72 + imageResponse = fetchImageResult.response; 73 + } 34 74 35 - if (url == null) { 36 - return getUrlErrorResponse(); 75 + if (!imageResponse.ok || imageResponse.body === null) { 76 + return new Response('"url" parameter is valid but upstream response is invalid', { 77 + status: imageResponse.status, 78 + }); 79 + } 80 + 81 + let immutable = false; 82 + if (parseResult.static) { 83 + immutable = true; 84 + } else { 85 + const cacheControlHeader = imageResponse.headers.get("Cache-Control"); 86 + if (cacheControlHeader !== null) { 87 + // TODO: Properly parse header 88 + immutable = cacheControlHeader.includes("immutable"); 37 89 } 90 + } 38 91 39 - // This method will never throw because URL parser will handle invalid input. 40 - const pathname = decodeURIComponent(url.pathname); 92 + const [contentTypeImageStream, imageStream] = imageResponse.body.tee(); 93 + const imageHeaderBytes = new Uint8Array(32); 94 + const contentTypeImageReader = contentTypeImageStream.getReader({ 95 + mode: "byob", 96 + }); 97 + const readImageHeaderBytesResult = await contentTypeImageReader.readAtLeast(32, imageHeaderBytes); 98 + if (readImageHeaderBytesResult.value === undefined) { 99 + await imageResponse.body.cancel(); 41 100 42 - NEXT_IMAGE_REGEXP ??= /\/_next\/image($|\/)/; 43 - if (NEXT_IMAGE_REGEXP.test(pathname)) { 44 - return getUrlErrorResponse(); 101 + return new Response('"url" parameter is valid but upstream response is invalid', { 102 + status: 400, 103 + }); 104 + } 105 + const contentType = detectImageContentType(readImageHeaderBytesResult.value); 106 + if (contentType === null) { 107 + warn(`Failed to detect content type of "${parseResult.url}"`); 108 + return new Response('"url" parameter is valid but image type is not allowed', { 109 + status: 400, 110 + }); 111 + } 112 + if (contentType === SVG) { 113 + if (!__IMAGES_ALLOW_SVG__) { 114 + return new Response('"url" parameter is valid but image type is not allowed', { 115 + status: 400, 116 + }); 117 + } 118 + const response = createImageResponse(imageStream, contentType, { 119 + immutable, 120 + }); 121 + return response; 122 + } 123 + 124 + if (contentType === GIF) { 125 + if (env.IMAGES === undefined) { 126 + warn("env.IMAGES binding is not defined"); 127 + const response = createImageResponse(imageStream, contentType, { 128 + immutable, 129 + }); 130 + return response; 45 131 } 46 132 47 - // If localPatterns are not defined all local images are allowed. 48 - if ( 49 - __IMAGES_LOCAL_PATTERNS__.length > 0 && 50 - !__IMAGES_LOCAL_PATTERNS__.some((p: LocalPattern) => matchLocalPattern(p, url)) 51 - ) { 52 - return getUrlErrorResponse(); 133 + const imageSource = env.IMAGES.input(imageStream); 134 + const imageTransformationResult = await imageSource 135 + .transform({ 136 + width: parseResult.width, 137 + fit: "scale-down", 138 + }) 139 + .output({ 140 + quality: parseResult.quality, 141 + format: GIF, 142 + }); 143 + const outputImageStream = imageTransformationResult.image(); 144 + const response = createImageResponse(outputImageStream, GIF, { 145 + immutable, 146 + }); 147 + return response; 148 + } 149 + 150 + if (contentType === AVIF || contentType === WEBP || contentType === JPEG || contentType === PNG) { 151 + if (env.IMAGES === undefined) { 152 + warn("env.IMAGES binding is not defined"); 153 + const response = createImageResponse(imageStream, contentType, { 154 + immutable, 155 + }); 156 + return response; 53 157 } 54 158 55 - return fetcher?.fetch(`http://assets.local${imageUrl}`); 159 + const outputFormat = parseResult.format ?? contentType; 160 + const imageSource = env.IMAGES.input(imageStream); 161 + const imageTransformationResult = await imageSource 162 + .transform({ 163 + width: parseResult.width, 164 + fit: "scale-down", 165 + }) 166 + .output({ 167 + quality: parseResult.quality, 168 + format: outputFormat, 169 + }); 170 + const outputImageStream = imageTransformationResult.image(); 171 + const response = createImageResponse(outputImageStream, outputFormat, { 172 + immutable, 173 + }); 174 + return response; 56 175 } 57 176 58 - // Remote 59 - let url: URL; 177 + warn(`Image content type ${contentType} not supported`); 178 + 179 + const response = createImageResponse(imageStream, contentType, { 180 + immutable, 181 + }); 182 + 183 + return response; 184 + } 185 + 186 + /** 187 + * Fetch call with max redirects and timeouts. 188 + * 189 + * Re-throws the exception thrown by a fetch call. 190 + * @param url 191 + * @param timeoutMS Timeout for a single fetch call. 192 + * @param maxRedirectCount 193 + * @returns 194 + */ 195 + async function fetchWithRedirects( 196 + url: string, 197 + timeoutMS: number, 198 + maxRedirectCount: number 199 + ): Promise<FetchWithRedirectsResult> { 200 + // TODO: Add dangerouslyAllowLocalIP support 201 + 202 + let response: Response; 60 203 try { 61 - url = new URL(imageUrl); 62 - } catch { 63 - return getUrlErrorResponse(); 204 + response = await fetch(url, { 205 + signal: AbortSignal.timeout(timeoutMS), 206 + redirect: "manual", 207 + }); 208 + } catch (e) { 209 + if (e instanceof Error && e.name === "TimeoutError") { 210 + const result: FetchWithRedirectsErrorResult = { 211 + ok: false, 212 + error: "timed_out", 213 + }; 214 + return result; 215 + } 216 + throw e; 217 + } 218 + if (redirectResponseStatuses.includes(response.status)) { 219 + const locationHeader = response.headers.get("Location"); 220 + if (locationHeader !== null) { 221 + if (maxRedirectCount < 1) { 222 + const result: FetchWithRedirectsErrorResult = { 223 + ok: false, 224 + error: "too_many_redirects", 225 + }; 226 + return result; 227 + } 228 + let redirectTarget: string; 229 + if (locationHeader.startsWith("/")) { 230 + redirectTarget = new URL(locationHeader, url).href; 231 + } else { 232 + redirectTarget = locationHeader; 233 + } 234 + const result = await fetchWithRedirects(redirectTarget, timeoutMS, maxRedirectCount - 1); 235 + return result; 236 + } 64 237 } 238 + const result: FetchWithRedirectsSuccessResult = { 239 + ok: true, 240 + response: response, 241 + }; 242 + return result; 243 + } 65 244 66 - if (url.protocol !== "http:" && url.protocol !== "https:") { 67 - return getUrlErrorResponse(); 68 - } 245 + type FetchWithRedirectsResult = FetchWithRedirectsSuccessResult | FetchWithRedirectsErrorResult; 69 246 70 - // The remotePatterns is used to allow images from specific remote external paths and block all others. 71 - if (!__IMAGES_REMOTE_PATTERNS__.some((p: RemotePattern) => matchRemotePattern(p, url))) { 72 - return getUrlErrorResponse(); 247 + type FetchWithRedirectsSuccessResult = { 248 + ok: true; 249 + response: Response; 250 + }; 251 + 252 + type FetchWithRedirectsErrorResult = { 253 + ok: false; 254 + error: FetchImageError; 255 + }; 256 + 257 + type FetchImageError = "timed_out" | "too_many_redirects"; 258 + 259 + const redirectResponseStatuses = [301, 302, 303, 307, 308]; 260 + 261 + function createImageResponse( 262 + image: ReadableStream, 263 + contentType: string, 264 + imageResponseFlags: ImageResponseFlags 265 + ): Response { 266 + const response = new Response(image, { 267 + headers: { 268 + Vary: "Accept", 269 + "Content-Type": contentType, 270 + "Content-Disposition": __IMAGES_CONTENT_DISPOSITION__, 271 + "Content-Security-Policy": __IMAGES_CONTENT_SECURITY_POLICY__, 272 + }, 273 + }); 274 + if (imageResponseFlags.immutable) { 275 + response.headers.set("Cache-Control", "public, max-age=315360000, immutable"); 73 276 } 277 + return response; 278 + } 74 279 75 - const imgResponse = await fetch(imageUrl, { cf: { cacheEverything: true } }); 280 + type ImageResponseFlags = { 281 + immutable: boolean; 282 + }; 283 + 284 + /** 285 + * Parses the image request URL and headers. 286 + * 287 + * This function validates the parameters and returns either the parsed result or an error message. 288 + * 289 + * @param requestURL request URL 290 + * @param requestHeaders request headers 291 + * @returns an instance of `ParseImageRequestURLSuccessResult` when successful, or an instance of `ErrorResult` when failed. 292 + */ 293 + function parseImageRequest( 294 + requestURL: URL, 295 + requestHeaders: Headers 296 + ): ParseImageRequestURLSuccessResult | ErrorResult { 297 + const formats = __IMAGES_FORMATS__; 76 298 77 - if (!imgResponse.body) { 78 - return imgResponse; 299 + const parsedUrlOrError = validateUrlQueryParameter(requestURL); 300 + if (!("url" in parsedUrlOrError)) { 301 + return parsedUrlOrError; 79 302 } 80 303 81 - const buffer = new ArrayBuffer(32); 304 + const widthOrError = validateWidthQueryParameter(requestURL); 305 + if (typeof widthOrError !== "number") { 306 + return widthOrError; 307 + } 82 308 83 - try { 84 - let contentType: string | undefined; 85 - // respBody is eventually used for the response 86 - // contentBody is used to detect the content type 87 - const [respBody, contentBody] = imgResponse.body.tee(); 88 - const reader = contentBody.getReader({ mode: "byob" }); 89 - const { value } = await reader.read(new Uint8Array(buffer)); 90 - // Release resources by calling `reader.cancel()` 91 - // `ctx.waitUntil` keeps the runtime running until the promise settles without having to wait here. 92 - ctx.waitUntil(reader.cancel()); 309 + const qualityOrError = validateQualityQueryParameter(requestURL); 310 + if (typeof qualityOrError !== "number") { 311 + return qualityOrError; 312 + } 93 313 94 - if (value) { 95 - contentType = detectContentType(value); 314 + const acceptHeader = requestHeaders.get("Accept") ?? ""; 315 + let format: OptimizedImageFormat | null = null; 316 + // Find a more specific format that the client accepts. 317 + for (const allowedFormat of formats) { 318 + if (acceptHeader.includes(allowedFormat)) { 319 + format = allowedFormat; 320 + break; 96 321 } 322 + } 97 323 98 - if (!contentType) { 99 - // Fallback to upstream header when the type can not be detected 100 - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L748 101 - contentType = imgResponse.headers.get("content-type") ?? ""; 324 + const result: ParseImageRequestURLSuccessResult = { 325 + ok: true, 326 + url: parsedUrlOrError.url, 327 + width: widthOrError, 328 + quality: qualityOrError, 329 + format, 330 + static: parsedUrlOrError.static, 331 + }; 332 + return result; 333 + } 334 + 335 + type ParseImageRequestURLSuccessResult = { 336 + ok: true; 337 + /** Absolute or relative URL. */ 338 + url: string; 339 + width: number; 340 + quality: number; 341 + format: OptimizedImageFormat | null; 342 + static: boolean; 343 + }; 344 + 345 + export type OptimizedImageFormat = "image/avif" | "image/webp"; 346 + 347 + type ErrorResult = { 348 + ok: false; 349 + message: string; 350 + }; 351 + 352 + /** 353 + * Validates that there is exactly one "url" query parameter. 354 + * 355 + * @returns the validated URL or an error result. 356 + */ 357 + function validateUrlQueryParameter(requestURL: URL): ErrorResult | { url: string; static: boolean } { 358 + // There should be a single "url" parameter. 359 + const urls = requestURL.searchParams.getAll("url"); 360 + if (urls.length < 1) { 361 + const result: ErrorResult = { 362 + ok: false, 363 + message: '"url" parameter is required', 364 + }; 365 + return result; 366 + } 367 + if (urls.length > 1) { 368 + const result: ErrorResult = { 369 + ok: false, 370 + message: '"url" parameter cannot be an array', 371 + }; 372 + return result; 373 + } 374 + 375 + // The url parameter value should be a valid URL or a valid relative URL. 376 + const url = urls[0]!; 377 + if (url.length > 3072) { 378 + const result: ErrorResult = { 379 + ok: false, 380 + message: '"url" parameter is too long', 381 + }; 382 + return result; 383 + } 384 + if (url.startsWith("//")) { 385 + const result: ErrorResult = { 386 + ok: false, 387 + message: '"url" parameter cannot be a protocol-relative URL (//)', 388 + }; 389 + return result; 390 + } 391 + 392 + if (url.startsWith("/")) { 393 + const staticAsset = url.startsWith(`${__NEXT_BASE_PATH__ || ""}/_next/static/media`); 394 + 395 + const pathname = getPathnameFromRelativeURL(url); 396 + if (/\/_next\/image($|\/)/.test(decodeURIComponent(pathname))) { 397 + const result: ErrorResult = { 398 + ok: false, 399 + message: '"url" parameter cannot be recursive', 400 + }; 401 + return result; 102 402 } 103 403 104 - // Sanitize the content type: 105 - // - Accept images only 106 - // - Reject multiple content types 107 - if (!contentType.startsWith("image/") || contentType.includes(",")) { 108 - contentType = undefined; 404 + if (!staticAsset) { 405 + if (!hasLocalMatch(__IMAGES_LOCAL_PATTERNS__, url)) { 406 + const result: ErrorResult = { ok: false, message: '"url" parameter is not allowed' }; 407 + return result; 408 + } 109 409 } 110 410 111 - if (contentType && !(contentType === SVG && !__IMAGES_ALLOW_SVG__)) { 112 - const headers = new Headers(imgResponse.headers); 113 - headers.set("content-type", contentType); 114 - headers.set("content-disposition", __IMAGES_CONTENT_DISPOSITION__); 115 - headers.set("content-security-policy", __IMAGES_CONTENT_SECURITY_POLICY__); 116 - return new Response(respBody, { ...imgResponse, headers }); 411 + return { url, static: staticAsset }; 412 + } 413 + 414 + let parsedURL: URL; 415 + try { 416 + parsedURL = new URL(url); 417 + } catch { 418 + const result: ErrorResult = { ok: false, message: '"url" parameter is invalid' }; 419 + return result; 420 + } 421 + 422 + const validProtocols = ["http:", "https:"]; 423 + if (!validProtocols.includes(parsedURL.protocol)) { 424 + const result: ErrorResult = { 425 + ok: false, 426 + message: '"url" parameter is invalid', 427 + }; 428 + return result; 429 + } 430 + if (!hasRemoteMatch(__IMAGES_REMOTE_PATTERNS__, parsedURL)) { 431 + const result: ErrorResult = { 432 + ok: false, 433 + message: '"url" parameter is not allowed', 434 + }; 435 + return result; 436 + } 437 + 438 + return { url: parsedURL.href, static: false }; 439 + } 440 + 441 + /** 442 + * Validates the "w" (width) query parameter. 443 + * 444 + * @returns the validated width number or an error result. 445 + */ 446 + function validateWidthQueryParameter(requestURL: URL): ErrorResult | number { 447 + const widthQueryValues = requestURL.searchParams.getAll("w"); 448 + if (widthQueryValues.length < 1) { 449 + const result: ErrorResult = { 450 + ok: false, 451 + message: '"w" parameter (width) is required', 452 + }; 453 + return result; 454 + } 455 + if (widthQueryValues.length > 1) { 456 + const result: ErrorResult = { 457 + ok: false, 458 + message: '"w" parameter (width) cannot be an array', 459 + }; 460 + return result; 461 + } 462 + const widthQueryValue = widthQueryValues[0]!; 463 + if (!/^[0-9]+$/.test(widthQueryValue)) { 464 + const result: ErrorResult = { 465 + ok: false, 466 + message: '"w" parameter (width) must be an integer greater than 0', 467 + }; 468 + return result; 469 + } 470 + const width = parseInt(widthQueryValue, 10); 471 + if (width <= 0 || isNaN(width)) { 472 + const result: ErrorResult = { 473 + ok: false, 474 + message: '"w" parameter (width) must be an integer greater than 0', 475 + }; 476 + return result; 477 + } 478 + 479 + const sizeValid = __IMAGES_DEVICE_SIZES__.includes(width) || __IMAGES_IMAGE_SIZES__.includes(width); 480 + if (!sizeValid) { 481 + const result: ErrorResult = { 482 + ok: false, 483 + message: `"w" parameter (width) of ${width} is not allowed`, 484 + }; 485 + return result; 486 + } 487 + 488 + return width; 489 + } 490 + 491 + /** 492 + * Validates the "q" (quality) query parameter. 493 + * 494 + * @returns the validated quality number or an error result. 495 + */ 496 + function validateQualityQueryParameter(requestURL: URL): ErrorResult | number { 497 + const qualityQueryValues = requestURL.searchParams.getAll("q"); 498 + if (qualityQueryValues.length < 1) { 499 + const result: ErrorResult = { 500 + ok: false, 501 + message: '"q" parameter (quality) is required', 502 + }; 503 + return result; 504 + } 505 + if (qualityQueryValues.length > 1) { 506 + const result: ErrorResult = { 507 + ok: false, 508 + message: '"q" parameter (quality) cannot be an array', 509 + }; 510 + return result; 511 + } 512 + const qualityQueryValue = qualityQueryValues[0]!; 513 + if (!/^[0-9]+$/.test(qualityQueryValue)) { 514 + const result: ErrorResult = { 515 + ok: false, 516 + message: '"q" parameter (quality) must be an integer between 1 and 100', 517 + }; 518 + return result; 519 + } 520 + const quality = parseInt(qualityQueryValue, 10); 521 + if (isNaN(quality) || quality < 1 || quality > 100) { 522 + const result: ErrorResult = { 523 + ok: false, 524 + message: '"q" parameter (quality) must be an integer between 1 and 100', 525 + }; 526 + return result; 527 + } 528 + if (!__IMAGES_QUALITIES__.includes(quality)) { 529 + const result: ErrorResult = { 530 + ok: false, 531 + message: `"q" parameter (quality) of ${quality} is not allowed`, 532 + }; 533 + return result; 534 + } 535 + 536 + return quality; 537 + } 538 + 539 + function getPathnameFromRelativeURL(relativeURL: string): string { 540 + return relativeURL.split("?")[0]!; 541 + } 542 + 543 + function hasLocalMatch(localPatterns: LocalPattern[], relativeURL: string): boolean { 544 + const parseRelativeURLResult = parseRelativeURL(relativeURL); 545 + for (const localPattern of localPatterns) { 546 + const matched = matchLocalPattern(localPattern, parseRelativeURLResult); 547 + if (matched) { 548 + return true; 117 549 } 550 + } 551 + return false; 552 + } 118 553 119 - // Cancel the unused stream 120 - ctx.waitUntil(respBody.cancel()); 554 + function parseRelativeURL(relativeURL: string): ParseRelativeURLResult { 555 + if (!relativeURL.includes("?")) { 556 + const result: ParseRelativeURLResult = { 557 + pathname: relativeURL, 558 + search: "", 559 + }; 560 + return result; 561 + } 562 + const parts = relativeURL.split("?"); 563 + const pathname = parts[0]!; 564 + const search = "?" + parts.slice(1).join("?"); 565 + const result: ParseRelativeURLResult = { 566 + pathname, 567 + search, 568 + }; 569 + return result; 570 + } 121 571 122 - return new Response('"url" parameter is valid but image type is not allowed', { 123 - status: 400, 124 - }); 125 - } catch { 126 - return new Response('"url" parameter is valid but upstream response is invalid', { 127 - status: 400, 128 - }); 572 + type ParseRelativeURLResult = { 573 + pathname: string; 574 + search: string; 575 + }; 576 + 577 + export function matchLocalPattern(pattern: LocalPattern, url: { pathname: string; search: string }): boolean { 578 + if (pattern.search !== undefined && pattern.search !== url.search) { 579 + return false; 129 580 } 581 + 582 + return new RegExp(pattern.pathname).test(url.pathname); 583 + } 584 + 585 + function hasRemoteMatch(remotePatterns: RemotePattern[], url: URL): boolean { 586 + for (const remotePattern of remotePatterns) { 587 + const matched = matchRemotePattern(remotePattern, url); 588 + if (matched) { 589 + return true; 590 + } 591 + } 592 + return false; 130 593 } 131 594 132 595 export function matchRemotePattern(pattern: RemotePattern, url: URL): boolean { ··· 154 617 return new RegExp(pattern.pathname).test(url.pathname); 155 618 } 156 619 157 - export function matchLocalPattern(pattern: LocalPattern, url: URL): boolean { 158 - // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/shared/lib/match-local-pattern.ts 159 - if (pattern.search !== undefined && pattern.search !== url.search) { 160 - return false; 161 - } 162 - 163 - return new RegExp(pattern.pathname).test(url.pathname); 164 - } 165 - 166 - /** 167 - * @returns same error as Next.js when the url query parameter is not accepted. 168 - */ 169 - function getUrlErrorResponse() { 170 - return new Response(`"url" parameter is not allowed`, { status: 400 }); 171 - } 172 - 173 620 const AVIF = "image/avif"; 174 621 const WEBP = "image/webp"; 175 622 const PNG = "image/png"; ··· 183 630 const ICNS = "image/x-icns"; 184 631 const TIFF = "image/tiff"; 185 632 const BMP = "image/bmp"; 186 - // pdf will be rejected (not an `image/...` type) 187 - const PDF = "application/pdf"; 633 + 634 + type ImageContentType = 635 + | "image/avif" 636 + | "image/webp" 637 + | "image/png" 638 + | "image/jpeg" 639 + | "image/jxl" 640 + | "image/jp2" 641 + | "image/heic" 642 + | "image/gif" 643 + | "image/svg+xml" 644 + | "image/x-icon" 645 + | "image/x-icns" 646 + | "image/tiff" 647 + | "image/bmp"; 188 648 189 649 /** 190 650 * Detects the content type by looking at the first few bytes of a file ··· 194 654 * @param buffer The image bytes 195 655 * @returns a content type of undefined for unsupported content 196 656 */ 197 - export function detectContentType(buffer: Uint8Array) { 657 + export function detectImageContentType(buffer: Uint8Array): ImageContentType | null { 198 658 if ([0xff, 0xd8, 0xff].every((b, i) => buffer[i] === b)) { 199 659 return JPEG; 200 660 } ··· 239 699 if ([0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63].every((b, i) => !b || buffer[i] === b)) { 240 700 return HEIC; 241 701 } 242 - if ([0x25, 0x50, 0x44, 0x46, 0x2d].every((b, i) => buffer[i] === b)) { 243 - return PDF; 244 - } 245 702 if ( 246 703 [0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b) 247 704 ) { 248 705 return JP2; 249 706 } 707 + return null; 250 708 } 251 709 252 710 declare global { 253 711 var __IMAGES_REMOTE_PATTERNS__: RemotePattern[]; 254 712 var __IMAGES_LOCAL_PATTERNS__: LocalPattern[]; 713 + var __IMAGES_DEVICE_SIZES__: number[]; 714 + var __IMAGES_IMAGE_SIZES__: number[]; 715 + var __IMAGES_QUALITIES__: number[]; 716 + var __IMAGES_FORMATS__: NextConfigImageFormat[]; 717 + var __IMAGES_MINIMUM_CACHE_TTL_SEC__: number; 255 718 var __IMAGES_ALLOW_SVG__: boolean; 256 719 var __IMAGES_CONTENT_SECURITY_POLICY__: string; 257 720 var __IMAGES_CONTENT_DISPOSITION__: string; 721 + var __IMAGES_MAX_REDIRECTS__: number; 722 + 723 + type NextConfigImageFormat = "image/avif" | "image/webp"; 258 724 }
+2 -4
packages/cloudflare/src/cli/templates/worker.ts
··· 1 1 //@ts-expect-error: Will be resolved by wrangler build 2 - import { fetchImage } from "./cloudflare/images.js"; 2 + import { handleImageRequest } from "./cloudflare/images.js"; 3 3 //@ts-expect-error: Will be resolved by wrangler build 4 4 import { runWithCloudflareRequestContext } from "./cloudflare/init.js"; 5 5 //@ts-expect-error: Will be resolved by wrangler build 6 6 import { maybeGetSkewProtectionResponse } from "./cloudflare/skew-protection.js"; 7 7 // @ts-expect-error: Will be resolved by wrangler build 8 8 import { handler as middlewareHandler } from "./middleware/handler.mjs"; 9 - 10 9 //@ts-expect-error: Will be resolved by wrangler build 11 10 export { DOQueueHandler } from "./.build/durable-objects/queue.js"; 12 11 //@ts-expect-error: Will be resolved by wrangler build ··· 43 42 url.pathname === 44 43 `${globalThis.__NEXT_BASE_PATH__}/_next/image${globalThis.__TRAILING_SLASH__ ? "/" : ""}` 45 44 ) { 46 - const imageUrl = url.searchParams.get("url") ?? ""; 47 - return await fetchImage(env.ASSETS, imageUrl, ctx); 45 + return await handleImageRequest(url, request.headers, env); 48 46 } 49 47 50 48 // - `Request`s are handled by the Next server
+372 -93
pnpm-lock.yaml
··· 911 911 '@types/node': 912 912 specifier: 'catalog:' 913 913 version: 22.2.0 914 + sharp: 915 + specifier: ^0.34.5 916 + version: 0.34.5 914 917 wrangler: 915 918 specifier: 'catalog:' 916 919 version: 4.49.1(@cloudflare/workers-types@4.20250924.0) ··· 1854 1857 resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} 1855 1858 engines: {node: '>=16'} 1856 1859 1857 - '@emnapi/runtime@1.4.3': 1858 - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} 1859 - 1860 1860 '@emnapi/runtime@1.4.5': 1861 1861 resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} 1862 + 1863 + '@emnapi/runtime@1.7.1': 1864 + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} 1862 1865 1863 1866 '@esbuild-kit/core-utils@3.3.2': 1864 1867 resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} ··· 3119 3122 resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 3120 3123 engines: {node: '>=18.18'} 3121 3124 3125 + '@img/colour@1.0.0': 3126 + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} 3127 + engines: {node: '>=18'} 3128 + 3122 3129 '@img/sharp-darwin-arm64@0.33.5': 3123 3130 resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} 3124 3131 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3131 3138 cpu: [arm64] 3132 3139 os: [darwin] 3133 3140 3141 + '@img/sharp-darwin-arm64@0.34.5': 3142 + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} 3143 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3144 + cpu: [arm64] 3145 + os: [darwin] 3146 + 3134 3147 '@img/sharp-darwin-x64@0.33.5': 3135 3148 resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} 3136 3149 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3143 3156 cpu: [x64] 3144 3157 os: [darwin] 3145 3158 3159 + '@img/sharp-darwin-x64@0.34.5': 3160 + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} 3161 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3162 + cpu: [x64] 3163 + os: [darwin] 3164 + 3146 3165 '@img/sharp-libvips-darwin-arm64@1.0.4': 3147 3166 resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} 3148 3167 cpu: [arm64] ··· 3153 3172 cpu: [arm64] 3154 3173 os: [darwin] 3155 3174 3175 + '@img/sharp-libvips-darwin-arm64@1.2.4': 3176 + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} 3177 + cpu: [arm64] 3178 + os: [darwin] 3179 + 3156 3180 '@img/sharp-libvips-darwin-x64@1.0.4': 3157 3181 resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} 3158 3182 cpu: [x64] ··· 3163 3187 cpu: [x64] 3164 3188 os: [darwin] 3165 3189 3190 + '@img/sharp-libvips-darwin-x64@1.2.4': 3191 + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} 3192 + cpu: [x64] 3193 + os: [darwin] 3194 + 3166 3195 '@img/sharp-libvips-linux-arm64@1.0.4': 3167 3196 resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} 3168 3197 cpu: [arm64] ··· 3170 3199 3171 3200 '@img/sharp-libvips-linux-arm64@1.2.0': 3172 3201 resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} 3202 + cpu: [arm64] 3203 + os: [linux] 3204 + 3205 + '@img/sharp-libvips-linux-arm64@1.2.4': 3206 + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} 3173 3207 cpu: [arm64] 3174 3208 os: [linux] 3175 3209 ··· 3183 3217 cpu: [arm] 3184 3218 os: [linux] 3185 3219 3220 + '@img/sharp-libvips-linux-arm@1.2.4': 3221 + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} 3222 + cpu: [arm] 3223 + os: [linux] 3224 + 3186 3225 '@img/sharp-libvips-linux-ppc64@1.2.0': 3187 3226 resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} 3188 3227 cpu: [ppc64] 3189 3228 os: [linux] 3190 3229 3230 + '@img/sharp-libvips-linux-ppc64@1.2.4': 3231 + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} 3232 + cpu: [ppc64] 3233 + os: [linux] 3234 + 3235 + '@img/sharp-libvips-linux-riscv64@1.2.4': 3236 + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} 3237 + cpu: [riscv64] 3238 + os: [linux] 3239 + 3191 3240 '@img/sharp-libvips-linux-s390x@1.0.4': 3192 3241 resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} 3193 3242 cpu: [s390x] ··· 3198 3247 cpu: [s390x] 3199 3248 os: [linux] 3200 3249 3250 + '@img/sharp-libvips-linux-s390x@1.2.4': 3251 + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} 3252 + cpu: [s390x] 3253 + os: [linux] 3254 + 3201 3255 '@img/sharp-libvips-linux-x64@1.0.4': 3202 3256 resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} 3203 3257 cpu: [x64] ··· 3205 3259 3206 3260 '@img/sharp-libvips-linux-x64@1.2.0': 3207 3261 resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} 3262 + cpu: [x64] 3263 + os: [linux] 3264 + 3265 + '@img/sharp-libvips-linux-x64@1.2.4': 3266 + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} 3208 3267 cpu: [x64] 3209 3268 os: [linux] 3210 3269 ··· 3218 3277 cpu: [arm64] 3219 3278 os: [linux] 3220 3279 3280 + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': 3281 + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} 3282 + cpu: [arm64] 3283 + os: [linux] 3284 + 3221 3285 '@img/sharp-libvips-linuxmusl-x64@1.0.4': 3222 3286 resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} 3223 3287 cpu: [x64] ··· 3228 3292 cpu: [x64] 3229 3293 os: [linux] 3230 3294 3295 + '@img/sharp-libvips-linuxmusl-x64@1.2.4': 3296 + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} 3297 + cpu: [x64] 3298 + os: [linux] 3299 + 3231 3300 '@img/sharp-linux-arm64@0.33.5': 3232 3301 resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} 3233 3302 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3240 3309 cpu: [arm64] 3241 3310 os: [linux] 3242 3311 3312 + '@img/sharp-linux-arm64@0.34.5': 3313 + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} 3314 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3315 + cpu: [arm64] 3316 + os: [linux] 3317 + 3243 3318 '@img/sharp-linux-arm@0.33.5': 3244 3319 resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} 3245 3320 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3252 3327 cpu: [arm] 3253 3328 os: [linux] 3254 3329 3330 + '@img/sharp-linux-arm@0.34.5': 3331 + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} 3332 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3333 + cpu: [arm] 3334 + os: [linux] 3335 + 3255 3336 '@img/sharp-linux-ppc64@0.34.3': 3256 3337 resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} 3257 3338 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3258 3339 cpu: [ppc64] 3259 3340 os: [linux] 3260 3341 3342 + '@img/sharp-linux-ppc64@0.34.5': 3343 + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} 3344 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3345 + cpu: [ppc64] 3346 + os: [linux] 3347 + 3348 + '@img/sharp-linux-riscv64@0.34.5': 3349 + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} 3350 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3351 + cpu: [riscv64] 3352 + os: [linux] 3353 + 3261 3354 '@img/sharp-linux-s390x@0.33.5': 3262 3355 resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} 3263 3356 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3270 3363 cpu: [s390x] 3271 3364 os: [linux] 3272 3365 3366 + '@img/sharp-linux-s390x@0.34.5': 3367 + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} 3368 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3369 + cpu: [s390x] 3370 + os: [linux] 3371 + 3273 3372 '@img/sharp-linux-x64@0.33.5': 3274 3373 resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} 3275 3374 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3282 3381 cpu: [x64] 3283 3382 os: [linux] 3284 3383 3384 + '@img/sharp-linux-x64@0.34.5': 3385 + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} 3386 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3387 + cpu: [x64] 3388 + os: [linux] 3389 + 3285 3390 '@img/sharp-linuxmusl-arm64@0.33.5': 3286 3391 resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} 3287 3392 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3290 3395 3291 3396 '@img/sharp-linuxmusl-arm64@0.34.3': 3292 3397 resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} 3398 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3399 + cpu: [arm64] 3400 + os: [linux] 3401 + 3402 + '@img/sharp-linuxmusl-arm64@0.34.5': 3403 + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} 3293 3404 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3294 3405 cpu: [arm64] 3295 3406 os: [linux] ··· 3306 3417 cpu: [x64] 3307 3418 os: [linux] 3308 3419 3420 + '@img/sharp-linuxmusl-x64@0.34.5': 3421 + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} 3422 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3423 + cpu: [x64] 3424 + os: [linux] 3425 + 3309 3426 '@img/sharp-wasm32@0.33.5': 3310 3427 resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} 3311 3428 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3316 3433 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3317 3434 cpu: [wasm32] 3318 3435 3436 + '@img/sharp-wasm32@0.34.5': 3437 + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} 3438 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3439 + cpu: [wasm32] 3440 + 3319 3441 '@img/sharp-win32-arm64@0.34.3': 3320 3442 resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} 3443 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3444 + cpu: [arm64] 3445 + os: [win32] 3446 + 3447 + '@img/sharp-win32-arm64@0.34.5': 3448 + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} 3321 3449 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3322 3450 cpu: [arm64] 3323 3451 os: [win32] ··· 3334 3462 cpu: [ia32] 3335 3463 os: [win32] 3336 3464 3465 + '@img/sharp-win32-ia32@0.34.5': 3466 + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} 3467 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3468 + cpu: [ia32] 3469 + os: [win32] 3470 + 3337 3471 '@img/sharp-win32-x64@0.33.5': 3338 3472 resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} 3339 3473 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} ··· 3342 3476 3343 3477 '@img/sharp-win32-x64@0.34.3': 3344 3478 resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} 3479 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3480 + cpu: [x64] 3481 + os: [win32] 3482 + 3483 + '@img/sharp-win32-x64@0.34.5': 3484 + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} 3345 3485 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 3346 3486 cpu: [x64] 3347 3487 os: [win32] ··· 5888 6028 resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} 5889 6029 engines: {node: '>=8'} 5890 6030 5891 - detect-libc@2.0.3: 5892 - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} 5893 - engines: {node: '>=8'} 5894 - 5895 6031 detect-libc@2.0.4: 5896 6032 resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} 6033 + engines: {node: '>=8'} 6034 + 6035 + detect-libc@2.1.2: 6036 + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} 5897 6037 engines: {node: '>=8'} 5898 6038 5899 6039 devlop@1.1.0: ··· 6417 6557 eslint-import-resolver-webpack: 6418 6558 optional: true 6419 6559 6420 - eslint-plugin-import@2.30.0: 6421 - resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} 6422 - engines: {node: '>=4'} 6423 - peerDependencies: 6424 - '@typescript-eslint/parser': '*' 6425 - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 6426 - peerDependenciesMeta: 6427 - '@typescript-eslint/parser': 6428 - optional: true 6429 - 6430 6560 eslint-plugin-import@2.31.0: 6431 6561 resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} 6432 6562 engines: {node: '>=4'} ··· 8935 9065 engines: {node: '>=10'} 8936 9066 hasBin: true 8937 9067 9068 + semver@7.7.3: 9069 + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} 9070 + engines: {node: '>=10'} 9071 + hasBin: true 9072 + 8938 9073 send@1.2.0: 8939 9074 resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} 8940 9075 engines: {node: '>= 18'} ··· 8970 9105 8971 9106 sharp@0.34.3: 8972 9107 resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} 9108 + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 9109 + 9110 + sharp@0.34.5: 9111 + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} 8973 9112 engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 8974 9113 8975 9114 shebang-command@2.0.0: ··· 11633 11772 dependencies: 11634 11773 '@edge-runtime/primitives': 4.1.0 11635 11774 11636 - '@emnapi/runtime@1.4.3': 11775 + '@emnapi/runtime@1.4.5': 11637 11776 dependencies: 11638 11777 tslib: 2.8.1 11639 11778 optional: true 11640 11779 11641 - '@emnapi/runtime@1.4.5': 11780 + '@emnapi/runtime@1.7.1': 11642 11781 dependencies: 11643 11782 tslib: 2.8.1 11644 11783 optional: true ··· 12655 12794 12656 12795 '@humanwhocodes/retry@0.4.3': {} 12657 12796 12797 + '@img/colour@1.0.0': {} 12798 + 12658 12799 '@img/sharp-darwin-arm64@0.33.5': 12659 12800 optionalDependencies: 12660 12801 '@img/sharp-libvips-darwin-arm64': 1.0.4 ··· 12665 12806 '@img/sharp-libvips-darwin-arm64': 1.2.0 12666 12807 optional: true 12667 12808 12809 + '@img/sharp-darwin-arm64@0.34.5': 12810 + optionalDependencies: 12811 + '@img/sharp-libvips-darwin-arm64': 1.2.4 12812 + optional: true 12813 + 12668 12814 '@img/sharp-darwin-x64@0.33.5': 12669 12815 optionalDependencies: 12670 12816 '@img/sharp-libvips-darwin-x64': 1.0.4 ··· 12675 12821 '@img/sharp-libvips-darwin-x64': 1.2.0 12676 12822 optional: true 12677 12823 12824 + '@img/sharp-darwin-x64@0.34.5': 12825 + optionalDependencies: 12826 + '@img/sharp-libvips-darwin-x64': 1.2.4 12827 + optional: true 12828 + 12678 12829 '@img/sharp-libvips-darwin-arm64@1.0.4': 12679 12830 optional: true 12680 12831 12681 12832 '@img/sharp-libvips-darwin-arm64@1.2.0': 12833 + optional: true 12834 + 12835 + '@img/sharp-libvips-darwin-arm64@1.2.4': 12682 12836 optional: true 12683 12837 12684 12838 '@img/sharp-libvips-darwin-x64@1.0.4': 12685 12839 optional: true 12686 12840 12687 12841 '@img/sharp-libvips-darwin-x64@1.2.0': 12842 + optional: true 12843 + 12844 + '@img/sharp-libvips-darwin-x64@1.2.4': 12688 12845 optional: true 12689 12846 12690 12847 '@img/sharp-libvips-linux-arm64@1.0.4': ··· 12693 12850 '@img/sharp-libvips-linux-arm64@1.2.0': 12694 12851 optional: true 12695 12852 12853 + '@img/sharp-libvips-linux-arm64@1.2.4': 12854 + optional: true 12855 + 12696 12856 '@img/sharp-libvips-linux-arm@1.0.5': 12697 12857 optional: true 12698 12858 12699 12859 '@img/sharp-libvips-linux-arm@1.2.0': 12860 + optional: true 12861 + 12862 + '@img/sharp-libvips-linux-arm@1.2.4': 12700 12863 optional: true 12701 12864 12702 12865 '@img/sharp-libvips-linux-ppc64@1.2.0': 12703 12866 optional: true 12704 12867 12868 + '@img/sharp-libvips-linux-ppc64@1.2.4': 12869 + optional: true 12870 + 12871 + '@img/sharp-libvips-linux-riscv64@1.2.4': 12872 + optional: true 12873 + 12705 12874 '@img/sharp-libvips-linux-s390x@1.0.4': 12706 12875 optional: true 12707 12876 12708 12877 '@img/sharp-libvips-linux-s390x@1.2.0': 12709 12878 optional: true 12710 12879 12880 + '@img/sharp-libvips-linux-s390x@1.2.4': 12881 + optional: true 12882 + 12711 12883 '@img/sharp-libvips-linux-x64@1.0.4': 12712 12884 optional: true 12713 12885 12714 12886 '@img/sharp-libvips-linux-x64@1.2.0': 12715 12887 optional: true 12716 12888 12889 + '@img/sharp-libvips-linux-x64@1.2.4': 12890 + optional: true 12891 + 12717 12892 '@img/sharp-libvips-linuxmusl-arm64@1.0.4': 12718 12893 optional: true 12719 12894 12720 12895 '@img/sharp-libvips-linuxmusl-arm64@1.2.0': 12721 12896 optional: true 12722 12897 12898 + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': 12899 + optional: true 12900 + 12723 12901 '@img/sharp-libvips-linuxmusl-x64@1.0.4': 12724 12902 optional: true 12725 12903 12726 12904 '@img/sharp-libvips-linuxmusl-x64@1.2.0': 12905 + optional: true 12906 + 12907 + '@img/sharp-libvips-linuxmusl-x64@1.2.4': 12727 12908 optional: true 12728 12909 12729 12910 '@img/sharp-linux-arm64@0.33.5': ··· 12736 12917 '@img/sharp-libvips-linux-arm64': 1.2.0 12737 12918 optional: true 12738 12919 12920 + '@img/sharp-linux-arm64@0.34.5': 12921 + optionalDependencies: 12922 + '@img/sharp-libvips-linux-arm64': 1.2.4 12923 + optional: true 12924 + 12739 12925 '@img/sharp-linux-arm@0.33.5': 12740 12926 optionalDependencies: 12741 12927 '@img/sharp-libvips-linux-arm': 1.0.5 ··· 12746 12932 '@img/sharp-libvips-linux-arm': 1.2.0 12747 12933 optional: true 12748 12934 12935 + '@img/sharp-linux-arm@0.34.5': 12936 + optionalDependencies: 12937 + '@img/sharp-libvips-linux-arm': 1.2.4 12938 + optional: true 12939 + 12749 12940 '@img/sharp-linux-ppc64@0.34.3': 12750 12941 optionalDependencies: 12751 12942 '@img/sharp-libvips-linux-ppc64': 1.2.0 12752 12943 optional: true 12753 12944 12945 + '@img/sharp-linux-ppc64@0.34.5': 12946 + optionalDependencies: 12947 + '@img/sharp-libvips-linux-ppc64': 1.2.4 12948 + optional: true 12949 + 12950 + '@img/sharp-linux-riscv64@0.34.5': 12951 + optionalDependencies: 12952 + '@img/sharp-libvips-linux-riscv64': 1.2.4 12953 + optional: true 12954 + 12754 12955 '@img/sharp-linux-s390x@0.33.5': 12755 12956 optionalDependencies: 12756 12957 '@img/sharp-libvips-linux-s390x': 1.0.4 ··· 12761 12962 '@img/sharp-libvips-linux-s390x': 1.2.0 12762 12963 optional: true 12763 12964 12965 + '@img/sharp-linux-s390x@0.34.5': 12966 + optionalDependencies: 12967 + '@img/sharp-libvips-linux-s390x': 1.2.4 12968 + optional: true 12969 + 12764 12970 '@img/sharp-linux-x64@0.33.5': 12765 12971 optionalDependencies: 12766 12972 '@img/sharp-libvips-linux-x64': 1.0.4 ··· 12771 12977 '@img/sharp-libvips-linux-x64': 1.2.0 12772 12978 optional: true 12773 12979 12980 + '@img/sharp-linux-x64@0.34.5': 12981 + optionalDependencies: 12982 + '@img/sharp-libvips-linux-x64': 1.2.4 12983 + optional: true 12984 + 12774 12985 '@img/sharp-linuxmusl-arm64@0.33.5': 12775 12986 optionalDependencies: 12776 12987 '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 ··· 12781 12992 '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 12782 12993 optional: true 12783 12994 12995 + '@img/sharp-linuxmusl-arm64@0.34.5': 12996 + optionalDependencies: 12997 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 12998 + optional: true 12999 + 12784 13000 '@img/sharp-linuxmusl-x64@0.33.5': 12785 13001 optionalDependencies: 12786 13002 '@img/sharp-libvips-linuxmusl-x64': 1.0.4 ··· 12791 13007 '@img/sharp-libvips-linuxmusl-x64': 1.2.0 12792 13008 optional: true 12793 13009 13010 + '@img/sharp-linuxmusl-x64@0.34.5': 13011 + optionalDependencies: 13012 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 13013 + optional: true 13014 + 12794 13015 '@img/sharp-wasm32@0.33.5': 12795 13016 dependencies: 12796 - '@emnapi/runtime': 1.4.3 13017 + '@emnapi/runtime': 1.4.5 12797 13018 optional: true 12798 13019 12799 13020 '@img/sharp-wasm32@0.34.3': ··· 12801 13022 '@emnapi/runtime': 1.4.5 12802 13023 optional: true 12803 13024 13025 + '@img/sharp-wasm32@0.34.5': 13026 + dependencies: 13027 + '@emnapi/runtime': 1.7.1 13028 + optional: true 13029 + 12804 13030 '@img/sharp-win32-arm64@0.34.3': 12805 13031 optional: true 12806 13032 13033 + '@img/sharp-win32-arm64@0.34.5': 13034 + optional: true 13035 + 12807 13036 '@img/sharp-win32-ia32@0.33.5': 12808 13037 optional: true 12809 13038 12810 13039 '@img/sharp-win32-ia32@0.34.3': 13040 + optional: true 13041 + 13042 + '@img/sharp-win32-ia32@0.34.5': 12811 13043 optional: true 12812 13044 12813 13045 '@img/sharp-win32-x64@0.33.5': 12814 13046 optional: true 12815 13047 12816 13048 '@img/sharp-win32-x64@0.34.3': 13049 + optional: true 13050 + 13051 + '@img/sharp-win32-x64@0.34.5': 12817 13052 optional: true 12818 13053 12819 13054 '@isaacs/balanced-match@4.0.1': {} ··· 12957 13192 https-proxy-agent: 7.0.6 12958 13193 node-fetch: 2.7.0 12959 13194 nopt: 8.1.0 12960 - semver: 7.7.1 13195 + semver: 7.7.2 12961 13196 tar: 7.4.3 12962 13197 transitivePeerDependencies: 12963 13198 - encoding ··· 14889 15124 fast-glob: 3.3.3 14890 15125 is-glob: 4.0.3 14891 15126 minimatch: 9.0.5 14892 - semver: 7.7.1 15127 + semver: 7.7.2 14893 15128 ts-api-utils: 2.1.0(typescript@5.9.3) 14894 15129 typescript: 5.9.3 14895 15130 transitivePeerDependencies: ··· 14903 15138 fast-glob: 3.3.3 14904 15139 is-glob: 4.0.3 14905 15140 minimatch: 9.0.5 14906 - semver: 7.7.1 15141 + semver: 7.7.2 14907 15142 ts-api-utils: 1.4.3(typescript@5.7.3) 14908 15143 optionalDependencies: 14909 15144 typescript: 5.7.3 ··· 14918 15153 fast-glob: 3.3.3 14919 15154 is-glob: 4.0.3 14920 15155 minimatch: 9.0.5 14921 - semver: 7.7.1 15156 + semver: 7.7.2 14922 15157 ts-api-utils: 1.4.3(typescript@5.9.3) 14923 15158 optionalDependencies: 14924 15159 typescript: 5.9.3 ··· 15848 16083 15849 16084 detect-libc@2.0.2: {} 15850 16085 15851 - detect-libc@2.0.3: {} 15852 - 15853 16086 detect-libc@2.0.4: {} 16087 + 16088 + detect-libc@2.1.2: {} 15854 16089 15855 16090 devlop@1.1.0: 15856 16091 dependencies: ··· 16402 16637 '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) 16403 16638 eslint: 8.57.1 16404 16639 eslint-import-resolver-node: 0.3.9 16405 - 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) 16406 - 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) 16640 + 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) 16641 + 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) 16407 16642 eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) 16408 16643 eslint-plugin-react: 7.36.1(eslint@8.57.1) 16409 16644 eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) ··· 16422 16657 '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) 16423 16658 eslint: 8.57.1 16424 16659 eslint-import-resolver-node: 0.3.9 16425 - 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) 16660 + 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) 16426 16661 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) 16427 16662 eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) 16428 16663 eslint-plugin-react: 7.36.1(eslint@8.57.1) ··· 16442 16677 '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) 16443 16678 eslint: 9.11.1(jiti@1.21.6) 16444 16679 eslint-import-resolver-node: 0.3.9 16445 - 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)) 16680 + 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)) 16446 16681 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)) 16447 16682 eslint-plugin-jsx-a11y: 6.10.0(eslint@9.11.1(jiti@1.21.6)) 16448 16683 eslint-plugin-react: 7.37.4(eslint@9.11.1(jiti@1.21.6)) ··· 16462 16697 '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) 16463 16698 eslint: 9.19.0(jiti@1.21.6) 16464 16699 eslint-import-resolver-node: 0.3.9 16465 - 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)) 16700 + 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)) 16466 16701 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)) 16467 16702 eslint-plugin-jsx-a11y: 6.10.0(eslint@9.19.0(jiti@1.21.6)) 16468 16703 eslint-plugin-react: 7.37.4(eslint@9.19.0(jiti@1.21.6)) ··· 16482 16717 transitivePeerDependencies: 16483 16718 - supports-color 16484 16719 16485 - 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): 16720 + 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): 16486 16721 dependencies: 16487 16722 '@nolyfill/is-core-module': 1.0.39 16488 16723 debug: 4.4.0 16489 16724 enhanced-resolve: 5.17.1 16490 16725 eslint: 8.57.1 16491 - 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) 16726 + 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) 16492 16727 fast-glob: 3.3.2 16493 16728 get-tsconfig: 4.8.0 16494 16729 is-bun-module: 1.2.1 ··· 16501 16736 - eslint-import-resolver-webpack 16502 16737 - supports-color 16503 16738 16504 - 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): 16739 + 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): 16505 16740 dependencies: 16506 16741 '@nolyfill/is-core-module': 1.0.39 16507 16742 debug: 4.4.0 16508 16743 enhanced-resolve: 5.17.1 16509 16744 eslint: 8.57.1 16510 - 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) 16745 + 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) 16511 16746 fast-glob: 3.3.2 16512 16747 get-tsconfig: 4.8.0 16513 16748 is-bun-module: 1.2.1 16514 16749 is-glob: 4.0.3 16515 16750 optionalDependencies: 16516 - 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) 16751 + 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) 16517 16752 transitivePeerDependencies: 16518 16753 - '@typescript-eslint/parser' 16519 16754 - eslint-import-resolver-node 16520 16755 - eslint-import-resolver-webpack 16521 16756 - supports-color 16522 16757 16523 - 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)): 16758 + 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)): 16524 16759 dependencies: 16525 16760 '@nolyfill/is-core-module': 1.0.39 16526 16761 debug: 4.4.0 16527 16762 enhanced-resolve: 5.17.1 16528 16763 eslint: 9.11.1(jiti@1.21.6) 16529 - 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)) 16764 + 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)) 16530 16765 fast-glob: 3.3.2 16531 16766 get-tsconfig: 4.8.0 16532 16767 is-bun-module: 1.2.1 ··· 16539 16774 - eslint-import-resolver-webpack 16540 16775 - supports-color 16541 16776 16542 - 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)): 16777 + 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)): 16543 16778 dependencies: 16544 16779 '@nolyfill/is-core-module': 1.0.39 16545 16780 debug: 4.4.0 16546 16781 enhanced-resolve: 5.17.1 16547 16782 eslint: 9.19.0(jiti@1.21.6) 16548 - 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)) 16783 + 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)) 16549 16784 fast-glob: 3.3.2 16550 16785 get-tsconfig: 4.8.0 16551 16786 is-bun-module: 1.2.1 ··· 16558 16793 - eslint-import-resolver-webpack 16559 16794 - supports-color 16560 16795 16561 - 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): 16796 + 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): 16562 16797 dependencies: 16563 16798 debug: 3.2.7 16564 16799 optionalDependencies: 16565 16800 '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) 16566 16801 eslint: 8.57.1 16567 16802 eslint-import-resolver-node: 0.3.9 16568 - 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) 16803 + 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) 16569 16804 transitivePeerDependencies: 16570 16805 - supports-color 16571 16806 16572 - 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): 16807 + 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): 16573 16808 dependencies: 16574 16809 debug: 3.2.7 16575 16810 optionalDependencies: 16576 16811 '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) 16577 16812 eslint: 8.57.1 16578 16813 eslint-import-resolver-node: 0.3.9 16579 - 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) 16814 + 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) 16580 16815 transitivePeerDependencies: 16581 16816 - supports-color 16582 16817 16583 - 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)): 16818 + 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)): 16584 16819 dependencies: 16585 16820 debug: 3.2.7 16586 16821 optionalDependencies: 16587 16822 '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) 16588 16823 eslint: 9.11.1(jiti@1.21.6) 16589 16824 eslint-import-resolver-node: 0.3.9 16590 - 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)) 16825 + 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)) 16591 16826 transitivePeerDependencies: 16592 16827 - supports-color 16593 16828 16594 - 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)): 16829 + 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)): 16595 16830 dependencies: 16596 16831 debug: 3.2.7 16597 16832 optionalDependencies: 16598 16833 '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) 16599 16834 eslint: 9.19.0(jiti@1.21.6) 16600 16835 eslint-import-resolver-node: 0.3.9 16601 - 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)) 16836 + 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)) 16602 16837 transitivePeerDependencies: 16603 16838 - supports-color 16604 16839 ··· 16612 16847 transitivePeerDependencies: 16613 16848 - supports-color 16614 16849 16615 - 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): 16850 + 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): 16616 16851 dependencies: 16617 16852 debug: 3.2.7 16618 16853 optionalDependencies: 16619 16854 '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) 16620 16855 eslint: 8.57.1 16621 16856 eslint-import-resolver-node: 0.3.9 16622 - 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) 16857 + 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) 16858 + transitivePeerDependencies: 16859 + - supports-color 16860 + 16861 + 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): 16862 + dependencies: 16863 + debug: 3.2.7 16864 + optionalDependencies: 16865 + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) 16866 + eslint: 8.57.1 16867 + eslint-import-resolver-node: 0.3.9 16868 + 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) 16623 16869 transitivePeerDependencies: 16624 16870 - supports-color 16625 16871 16626 - 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)): 16872 + 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)): 16627 16873 dependencies: 16628 16874 debug: 3.2.7 16629 16875 optionalDependencies: 16630 16876 '@typescript-eslint/parser': 8.7.0(eslint@9.11.1(jiti@1.21.6))(typescript@5.7.3) 16631 16877 eslint: 9.11.1(jiti@1.21.6) 16632 16878 eslint-import-resolver-node: 0.3.9 16633 - 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)) 16879 + 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)) 16634 16880 transitivePeerDependencies: 16635 16881 - supports-color 16636 16882 16637 - 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)): 16883 + 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)): 16638 16884 dependencies: 16639 16885 debug: 3.2.7 16640 16886 optionalDependencies: 16641 16887 '@typescript-eslint/parser': 8.7.0(eslint@9.19.0(jiti@1.21.6))(typescript@5.7.3) 16642 16888 eslint: 9.19.0(jiti@1.21.6) 16643 16889 eslint-import-resolver-node: 0.3.9 16644 - 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)) 16645 - transitivePeerDependencies: 16646 - - supports-color 16647 - 16648 - 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): 16649 - dependencies: 16650 - '@rtsao/scc': 1.1.0 16651 - array-includes: 3.1.8 16652 - array.prototype.findlastindex: 1.2.6 16653 - array.prototype.flat: 1.3.3 16654 - array.prototype.flatmap: 1.3.3 16655 - debug: 3.2.7 16656 - doctrine: 2.1.0 16657 - eslint: 8.57.1 16658 - eslint-import-resolver-node: 0.3.9 16659 - 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) 16660 - hasown: 2.0.2 16661 - is-core-module: 2.16.1 16662 - is-glob: 4.0.3 16663 - minimatch: 3.1.2 16664 - object.fromentries: 2.0.8 16665 - object.groupby: 1.0.3 16666 - object.values: 1.2.1 16667 - semver: 6.3.1 16668 - tsconfig-paths: 3.15.0 16669 - optionalDependencies: 16670 - '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) 16890 + 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)) 16671 16891 transitivePeerDependencies: 16672 - - eslint-import-resolver-typescript 16673 - - eslint-import-resolver-webpack 16674 16892 - supports-color 16675 16893 16676 16894 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)): ··· 16713 16931 doctrine: 2.1.0 16714 16932 eslint: 8.57.1 16715 16933 eslint-import-resolver-node: 0.3.9 16716 - 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) 16934 + 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) 16935 + hasown: 2.0.2 16936 + is-core-module: 2.16.1 16937 + is-glob: 4.0.3 16938 + minimatch: 3.1.2 16939 + object.fromentries: 2.0.8 16940 + object.groupby: 1.0.3 16941 + object.values: 1.2.1 16942 + semver: 6.3.1 16943 + string.prototype.trimend: 1.0.9 16944 + tsconfig-paths: 3.15.0 16945 + optionalDependencies: 16946 + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) 16947 + transitivePeerDependencies: 16948 + - eslint-import-resolver-typescript 16949 + - eslint-import-resolver-webpack 16950 + - supports-color 16951 + 16952 + 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): 16953 + dependencies: 16954 + '@rtsao/scc': 1.1.0 16955 + array-includes: 3.1.8 16956 + array.prototype.findlastindex: 1.2.6 16957 + array.prototype.flat: 1.3.3 16958 + array.prototype.flatmap: 1.3.3 16959 + debug: 3.2.7 16960 + doctrine: 2.1.0 16961 + eslint: 8.57.1 16962 + eslint-import-resolver-node: 0.3.9 16963 + 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) 16717 16964 hasown: 2.0.2 16718 16965 is-core-module: 2.16.1 16719 16966 is-glob: 4.0.3 ··· 16725 16972 string.prototype.trimend: 1.0.9 16726 16973 tsconfig-paths: 3.15.0 16727 16974 optionalDependencies: 16728 - '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.7.3) 16975 + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.9.3) 16729 16976 transitivePeerDependencies: 16730 16977 - eslint-import-resolver-typescript 16731 16978 - eslint-import-resolver-webpack ··· 16742 16989 doctrine: 2.1.0 16743 16990 eslint: 9.11.1(jiti@1.21.6) 16744 16991 eslint-import-resolver-node: 0.3.9 16745 - 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)) 16992 + 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)) 16746 16993 hasown: 2.0.2 16747 16994 is-core-module: 2.16.1 16748 16995 is-glob: 4.0.3 ··· 16771 17018 doctrine: 2.1.0 16772 17019 eslint: 9.19.0(jiti@1.21.6) 16773 17020 eslint-import-resolver-node: 0.3.9 16774 - 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)) 17021 + 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)) 16775 17022 hasown: 2.0.2 16776 17023 is-core-module: 2.16.1 16777 17024 is-glob: 4.0.3 ··· 17967 18214 17968 18215 is-bun-module@1.2.1: 17969 18216 dependencies: 17970 - semver: 7.7.1 18217 + semver: 7.7.2 17971 18218 17972 18219 is-callable@1.2.7: {} 17973 18220 ··· 18210 18457 lodash.isstring: 4.0.1 18211 18458 lodash.once: 4.1.1 18212 18459 ms: 2.1.3 18213 - semver: 7.7.1 18460 + semver: 7.7.2 18214 18461 18215 18462 jsx-ast-utils@3.3.5: 18216 18463 dependencies: ··· 19031 19278 19032 19279 node-abi@3.73.0: 19033 19280 dependencies: 19034 - semver: 7.7.1 19281 + semver: 7.7.2 19035 19282 19036 19283 node-domexception@1.0.0: {} 19037 19284 ··· 19519 19766 19520 19767 prebuild-install@7.1.3: 19521 19768 dependencies: 19522 - detect-libc: 2.0.3 19769 + detect-libc: 2.0.4 19523 19770 expand-template: 2.0.3 19524 19771 github-from-package: 0.0.0 19525 19772 minimist: 1.2.8 ··· 19980 20227 19981 20228 semver@7.7.1: {} 19982 20229 19983 - semver@7.7.2: 19984 - optional: true 20230 + semver@7.7.2: {} 20231 + 20232 + semver@7.7.3: {} 19985 20233 19986 20234 send@1.2.0: 19987 20235 dependencies: ··· 20040 20288 dependencies: 20041 20289 color: 4.2.3 20042 20290 detect-libc: 2.0.4 20043 - semver: 7.7.1 20291 + semver: 7.7.2 20044 20292 optionalDependencies: 20045 20293 '@img/sharp-darwin-arm64': 0.33.5 20046 20294 '@img/sharp-darwin-x64': 0.33.5 ··· 20091 20339 '@img/sharp-win32-ia32': 0.34.3 20092 20340 '@img/sharp-win32-x64': 0.34.3 20093 20341 optional: true 20342 + 20343 + sharp@0.34.5: 20344 + dependencies: 20345 + '@img/colour': 1.0.0 20346 + detect-libc: 2.1.2 20347 + semver: 7.7.3 20348 + optionalDependencies: 20349 + '@img/sharp-darwin-arm64': 0.34.5 20350 + '@img/sharp-darwin-x64': 0.34.5 20351 + '@img/sharp-libvips-darwin-arm64': 1.2.4 20352 + '@img/sharp-libvips-darwin-x64': 1.2.4 20353 + '@img/sharp-libvips-linux-arm': 1.2.4 20354 + '@img/sharp-libvips-linux-arm64': 1.2.4 20355 + '@img/sharp-libvips-linux-ppc64': 1.2.4 20356 + '@img/sharp-libvips-linux-riscv64': 1.2.4 20357 + '@img/sharp-libvips-linux-s390x': 1.2.4 20358 + '@img/sharp-libvips-linux-x64': 1.2.4 20359 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 20360 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 20361 + '@img/sharp-linux-arm': 0.34.5 20362 + '@img/sharp-linux-arm64': 0.34.5 20363 + '@img/sharp-linux-ppc64': 0.34.5 20364 + '@img/sharp-linux-riscv64': 0.34.5 20365 + '@img/sharp-linux-s390x': 0.34.5 20366 + '@img/sharp-linux-x64': 0.34.5 20367 + '@img/sharp-linuxmusl-arm64': 0.34.5 20368 + '@img/sharp-linuxmusl-x64': 0.34.5 20369 + '@img/sharp-wasm32': 0.34.5 20370 + '@img/sharp-win32-arm64': 0.34.5 20371 + '@img/sharp-win32-ia32': 0.34.5 20372 + '@img/sharp-win32-x64': 0.34.5 20094 20373 20095 20374 shebang-command@2.0.0: 20096 20375 dependencies: