diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index d2d85815f7b7..8224f48e6876 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -83,10 +83,12 @@ "path-to-regexp": "^6.3.0", "resolve": "^1.22.8", "selfsigned": "^2.0.1", + "sharp": "^0.33.5", "source-map": "^0.6.1", "unenv": "npm:unenv-nightly@2.0.0-20241121-161142-806b5c0", "workerd": "1.20241106.1", - "xxhash-wasm": "^1.0.1" + "xxhash-wasm": "^1.0.1", + "zod": "^3.22.3" }, "devDependencies": { "@cloudflare/cli": "workspace:*", diff --git a/packages/wrangler/src/dev/miniflare.ts b/packages/wrangler/src/dev/miniflare.ts index a8b84a665175..270533ce39a9 100644 --- a/packages/wrangler/src/dev/miniflare.ts +++ b/packages/wrangler/src/dev/miniflare.ts @@ -41,7 +41,12 @@ import type { EsbuildBundle } from "./use-esbuild"; import type { MiniflareOptions, SourceOptions, WorkerOptions } from "miniflare"; import type { UUID } from "node:crypto"; import type { Readable } from "node:stream"; -import { EXTERNAL_IMAGES_WORKER_NAME, EXTERNAL_IMAGES_WORKER_SCRIPT, imagesFetcher } from "../images/fetcher"; +import { + EXTERNAL_IMAGES_WORKER_NAME, + EXTERNAL_IMAGES_WORKER_SCRIPT, + imagesLocalFetcher, + imagesRemoteFetcher, +} from "../images/fetcher"; // This worker proxies all external Durable Objects to the Wrangler session // where they're defined, and receives all requests from other Wrangler sessions @@ -613,7 +618,7 @@ export function buildMiniflareBindingOptions(config: MiniflareBindingsConfig): { } ], serviceBindings: { - FETCHER: config.imagesLocalMode ? imagesFetcher : imagesFetcher, + FETCHER: config.imagesLocalMode ? imagesLocalFetcher : imagesRemoteFetcher, } }); diff --git a/packages/wrangler/src/images/fetcher.ts b/packages/wrangler/src/images/fetcher.ts index f96d196bbff6..0287ab72c21b 100644 --- a/packages/wrangler/src/images/fetcher.ts +++ b/packages/wrangler/src/images/fetcher.ts @@ -1,4 +1,4 @@ -import { Headers, Response } from "miniflare"; +import { Response } from "miniflare"; import { performApiFetch } from "../cfetch/internal"; import { getAccountId } from "../user"; import type { Request } from "miniflare"; @@ -15,7 +15,7 @@ export default function (env) { } `; -export async function imagesFetcher(request: Request): Promise { +export async function imagesRemoteFetcher(request: Request): Promise { const accountId = await getAccountId(); const url = `/accounts/${accountId}/images_edge/v2/binding/preview${new URL(request.url).pathname}`; @@ -30,3 +30,5 @@ export async function imagesFetcher(request: Request): Promise { { headers: res.headers } ); } + +export { imagesLocalFetcher } from './local'; diff --git a/packages/wrangler/src/images/local.ts b/packages/wrangler/src/images/local.ts new file mode 100644 index 000000000000..a80878c54c72 --- /dev/null +++ b/packages/wrangler/src/images/local.ts @@ -0,0 +1,187 @@ +import { File } from "buffer"; +import sharp from "sharp"; +import { z } from "zod"; +import type { ImageInfoResponse } from "@cloudflare/workers-types/experimental"; +import type { Sharp } from "sharp"; + +const Transform = z.object({ + imageIndex: z.number().optional(), + rotate: z.number().optional(), + width: z.number().optional(), + height: z.number().optional(), +}); + +const Transforms = z.array(Transform); + +export async function imagesLocalFetcher(request: Request): Promise { + const data = await request.formData(); + + const body = data.get("image"); + if (!body || !(body instanceof File)) { + return errorResponse(400, 9523, "ERROR: Expected image in request"); + } + + const transformer = sharp(await body.arrayBuffer(), {}); + + const url = new URL(request.url); + + if (url.pathname == "/info") { + return runInfo(transformer); + } else { + const badTransformsResponse = errorResponse( + 400, + 9523, + "ERROR: Expected JSON array of valid transforms in transforms field" + ); + try { + const transformsJson = data.get("transforms"); + + if (typeof transformsJson !== "string") { + return badTransformsResponse; + } + + const transforms = Transforms.safeParse(JSON.parse(transformsJson)); + + if (!transforms.success) { + return badTransformsResponse; + } + + const outputFormat = data.get("output_format"); + + if (outputFormat != null && typeof outputFormat !== "string") { + return errorResponse( + 400, + 9523, + "ERROR: Expected output format to be a string if provided" + ); + } + + return runTransform(transformer, transforms.data, outputFormat); + } catch (e) { + return badTransformsResponse; + } + } +} + +async function runInfo(transformer: Sharp): Promise { + const metadata = await transformer.metadata(); + + let mime: string | null = null; + switch (metadata.format) { + case "jpeg": + mime = "image/jpeg"; + break; + case "svg": + mime = "image/svg+xml"; + break; + case "png": + mime = "image/png"; + break; + case "webp": + mime = "image/webp"; + break; + case "gif": + mime = "image/gif"; + break; + case "avif": + mime = "image/avif"; + break; + default: + return errorResponse(415, 9520, "ERROR: Unsupported image type"); + } + + let resp: ImageInfoResponse; + if (mime == "image/svg+xml") { + resp = { + format: mime, + }; + } else { + if (!metadata.size || !metadata.width || !metadata.height) { + return errorResponse( + 500, + 9523, + "ERROR: Expected size, width and height for bitmap input" + ); + } + + resp = { + format: mime, + fileSize: metadata.size, + width: metadata.width, + height: metadata.height, + }; + } + + return Response.json(resp); +} + +async function runTransform( + transformer: Sharp, + transforms: z.infer, + outputFormat: string | null +): Promise { + for (const transform of transforms) { + if (transform.imageIndex !== undefined && transform.imageIndex !== 0) { + // We don't support draws, and this transform doesn't apply to the root + // image, so skip it + continue; + } + + if (transform.rotate !== undefined) { + transformer.rotate(transform.rotate); + } + + if (transform.width !== undefined || transform.height !== undefined) { + transformer.resize(transform.width || null, transform.height || null, { + fit: "contain", + }); + } + } + + switch (outputFormat) { + case "image/avif": + transformer.avif(); + break; + case "image/gif": + return errorResponse( + 415, + 9520, + "ERROR: GIF output is not supported in local mode" + ); + case "image/jpeg": + transformer.jpeg(); + break; + case "image/png": + transformer.png(); + break; + case "image/webp": + transformer.webp(); + break; + case "rgb": + case "rgba": + return errorResponse( + 415, + 9520, + "ERROR: RGB/RGBA output is not supported in local mode" + ); + default: + outputFormat = "image/jpeg"; + break; + } + + return new Response(transformer, { + headers: { + "content-type": outputFormat, + }, + }); +} + +function errorResponse(status: number, code: number, message: string) { + return new Response(`ERROR ${code}: ${message}`, { + status, + headers: { + "content-type": "text/plain", + "cf-images-binding": `err=${code}`, + }, + }); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9922bf22f96d..005e1bd305c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -975,7 +975,7 @@ importers: version: 8.57.0 eslint-config-turbo: specifier: latest - version: 2.2.3(eslint@8.57.0) + version: 2.3.3(eslint@8.57.0) eslint-plugin-import: specifier: 2.26.x version: 2.26.0(@typescript-eslint/parser@6.10.0(eslint@8.57.0)(typescript@5.6.3))(eslint@8.57.0) @@ -1731,6 +1731,9 @@ importers: selfsigned: specifier: ^2.0.1 version: 2.1.1 + sharp: + specifier: ^0.33.5 + version: 0.33.5 source-map: specifier: ^0.6.1 version: 0.6.1 @@ -1743,6 +1746,9 @@ importers: xxhash-wasm: specifier: ^1.0.1 version: 1.0.1 + zod: + specifier: ^3.22.3 + version: 3.22.3 optionalDependencies: fsevents: specifier: ~2.3.2 @@ -2022,7 +2028,7 @@ packages: '@azure/core-http@3.0.4': resolution: {integrity: sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==} engines: {node: '>=14.0.0'} - deprecated: deprecating as we migrated to core v2 + deprecated: This package is no longer supported. Please migrate to use @azure/core-rest-pipeline '@azure/core-lro@2.5.4': resolution: {integrity: sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==} @@ -2523,6 +2529,9 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@emnapi/runtime@1.3.1': + resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild-kit/cjs-loader@2.4.4': resolution: {integrity: sha512-NfsJX4PdzhwSkfJukczyUiZGc7zNNWZcEAyqeISpDnn0PTfzMJR1aR8xAIPskBejIxBJbIgCCMzbaYa9SXepIg==} deprecated: 'Merged into tsx: https://tsx.is' @@ -3003,6 +3012,111 @@ packages: '@iarna/toml@3.0.0': resolution: {integrity: sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q==} + '@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} + 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} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + 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} + 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} + cpu: [arm] + 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} + 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} + 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} + 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} + 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} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + 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} + cpu: [x64] + os: [win32] + '@inquirer/confirm@3.2.0': resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==} engines: {node: '>=18'} @@ -4475,10 +4589,17 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -4787,6 +4908,10 @@ 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-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -4987,8 +5112,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-config-turbo@2.2.3: - resolution: {integrity: sha512-/zwNU+G2w0HszXzWILdl6/Catt86ejUG7vsFSdpnFzFAAUbbT2TxgoCFvC1fKtm6+SkQsXwkRRe9tFz0aMftpg==} + eslint-config-turbo@2.3.3: + resolution: {integrity: sha512-cM9wSBYowQIrjx2MPCzFE6jTnG4vpTPJKZ/O+Ps3CqrmGK/wtNOsY6WHGMwLtKY/nNbgRahAJH6jGVF6k2coOg==} peerDependencies: eslint: '>6.6.0' @@ -5062,8 +5187,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - eslint-plugin-turbo@2.2.3: - resolution: {integrity: sha512-LHt35VwxthdGVO6hQRfvmFb6ee8/exAzAYWCy4o87Bnp7urltP8qg7xMd4dPSLAhtfnI2xSo1WgeVaR3MeItxw==} + eslint-plugin-turbo@2.3.3: + resolution: {integrity: sha512-j8UEA0Z+NNCsjZep9G5u5soDQHcXq/x4amrwulk6eHF1U91H2qAjp5I4jQcvJewmccCJbVp734PkHHTRnosjpg==} peerDependencies: eslint: '>6.6.0' @@ -5741,6 +5866,9 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -7415,6 +7543,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -7452,6 +7585,10 @@ packages: shallow-equal@1.2.1: resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -7498,6 +7635,9 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sirv@2.0.4: resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} engines: {node: '>= 10'} @@ -9340,6 +9480,11 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@emnapi/runtime@1.3.1': + dependencies: + tslib: 2.5.3 + optional: true + '@esbuild-kit/cjs-loader@2.4.4': dependencies: '@esbuild-kit/core-utils': 3.3.2 @@ -9626,6 +9771,81 @@ snapshots: '@iarna/toml@3.0.0': {} + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.3.1 + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + '@inquirer/confirm@3.2.0': dependencies: '@inquirer/core': 9.2.1 @@ -11458,8 +11678,18 @@ snapshots: color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + color-support@1.1.3: {} + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -11738,6 +11968,8 @@ snapshots: detect-libc@2.0.2: {} + detect-libc@2.0.3: {} + detect-newline@3.1.0: {} devalue@4.3.2: {} @@ -12026,10 +12258,10 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-turbo@2.2.3(eslint@8.57.0): + eslint-config-turbo@2.3.3(eslint@8.57.0): dependencies: eslint: 8.57.0 - eslint-plugin-turbo: 2.2.3(eslint@8.57.0) + eslint-plugin-turbo: 2.3.3(eslint@8.57.0) eslint-import-resolver-node@0.3.7: dependencies: @@ -12113,7 +12345,7 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.8 - eslint-plugin-turbo@2.2.3(eslint@8.57.0): + eslint-plugin-turbo@2.3.3(eslint@8.57.0): dependencies: dotenv: 16.0.3 eslint: 8.57.0 @@ -12963,6 +13195,8 @@ snapshots: is-arrayish@0.2.1: {} + is-arrayish@0.3.2: {} + is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.0 @@ -14626,6 +14860,8 @@ snapshots: dependencies: lru-cache: 6.0.0 + semver@7.6.3: {} + send@0.18.0(supports-color@9.2.2): dependencies: debug: 2.6.9(supports-color@9.2.2) @@ -14685,6 +14921,32 @@ snapshots: shallow-equal@1.2.1: {} + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.6.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 @@ -14728,6 +14990,10 @@ snapshots: simple-concat: 1.0.1 optional: true + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + sirv@2.0.4: dependencies: '@polka/url': 1.0.0-next.25