From 0a4696c6537efc0ad7b44fa3f231c48f521a8ed4 Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Tue, 18 Aug 2026 18:08:01 +0100 Subject: [PATCH 1/2] test(storage-resize-images): add kit test suite Ports the extension's unit coverage to the kit and wires up `pnpm test` with vitest. Filters, path handling, image conversion, resize, the content filter and the resize handler carry over. The extension's config snapshot test does not apply now that config comes from Firebase params, so it is replaced with tests over `configFromEnv` and `resolveResizeImagesConfig`. Adds coverage the extension only had behind an emulator or a live project: the failed-image path guard against directory traversal, and the delete original file modes. --- kits/storage-resize-images/package-lock.json | 1193 ++++++++++++++++- kits/storage-resize-images/package.json | 6 +- .../tests/config.test.ts | 120 ++ .../tests/content-filter.test.ts | 280 ++++ .../tests/convert-image.test.ts | 85 ++ .../tests/export-config.test.ts | 136 ++ .../tests/file-operations.test.ts | 131 ++ .../tests/filters.test.ts | 129 ++ .../tests/handlers.test.ts | 273 ++++ kits/storage-resize-images/tests/lib.test.ts | 42 + .../tests/resize-image.test.ts | 245 ++++ .../tests/resize.test.ts | 91 ++ .../tests/retry-queue.test.ts | 161 +++ .../tests/test-image.gif | Bin 0 -> 207266 bytes .../tests/test-image.jpeg | Bin 0 -> 339 bytes .../tests/test-image.png | Bin 0 -> 420 bytes kits/storage-resize-images/tests/util.test.ts | 121 ++ 17 files changed, 3006 insertions(+), 7 deletions(-) create mode 100644 kits/storage-resize-images/tests/config.test.ts create mode 100644 kits/storage-resize-images/tests/content-filter.test.ts create mode 100644 kits/storage-resize-images/tests/convert-image.test.ts create mode 100644 kits/storage-resize-images/tests/export-config.test.ts create mode 100644 kits/storage-resize-images/tests/file-operations.test.ts create mode 100644 kits/storage-resize-images/tests/filters.test.ts create mode 100644 kits/storage-resize-images/tests/handlers.test.ts create mode 100644 kits/storage-resize-images/tests/lib.test.ts create mode 100644 kits/storage-resize-images/tests/resize-image.test.ts create mode 100644 kits/storage-resize-images/tests/resize.test.ts create mode 100644 kits/storage-resize-images/tests/retry-queue.test.ts create mode 100644 kits/storage-resize-images/tests/test-image.gif create mode 100644 kits/storage-resize-images/tests/test-image.jpeg create mode 100644 kits/storage-resize-images/tests/test-image.png create mode 100644 kits/storage-resize-images/tests/util.test.ts diff --git a/kits/storage-resize-images/package-lock.json b/kits/storage-resize-images/package-lock.json index e398655495..8a29ddc8fd 100644 --- a/kits/storage-resize-images/package-lock.json +++ b/kits/storage-resize-images/package-lock.json @@ -1,12 +1,12 @@ { - "name": "@firebase/storage-resize-images", - "version": "0.1.0", + "name": "@firebase-function-kits/storage-resize-images", + "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@firebase/storage-resize-images", - "version": "0.1.0", + "name": "@firebase-function-kits/storage-resize-images", + "version": "0.0.0", "license": "Apache-2.0", "dependencies": { "@genkit-ai/vertexai": "^1.2.0", @@ -19,6 +19,10 @@ "sharp": "^0.34.5", "uuid": "^11.0.5" }, + "devDependencies": { + "@genkit-ai/core": "^1.2.0", + "vitest": "^4.1.10" + }, "engines": { "node": ">=22" } @@ -2079,6 +2083,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, "node_modules/@js-sdsl/ordered-map": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", @@ -3484,6 +3495,16 @@ "@opentelemetry/api": "^1.1.0" } }, + "node_modules/@oxc-project/types": { + "version": "0.144.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.144.0.tgz", + "integrity": "sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3551,6 +3572,269 @@ "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", "license": "BSD-3-Clause" }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.4.tgz", + "integrity": "sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.4.tgz", + "integrity": "sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.4.tgz", + "integrity": "sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.4.tgz", + "integrity": "sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.4.tgz", + "integrity": "sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.4.tgz", + "integrity": "sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.4.tgz", + "integrity": "sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.4.tgz", + "integrity": "sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.4.tgz", + "integrity": "sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.4.tgz", + "integrity": "sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.4.tgz", + "integrity": "sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.4.tgz", + "integrity": "sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.4.tgz", + "integrity": "sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, "node_modules/@so-ric/colorspace": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", @@ -3562,6 +3846,13 @@ "text-hex": "1.0.x" } }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", @@ -3604,6 +3895,17 @@ "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", "license": "MIT" }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -3622,6 +3924,20 @@ "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/express": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", @@ -3856,6 +4172,119 @@ "license": "MIT", "optional": true }, + "node_modules/@vitest/expect": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.11", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -4025,8 +4454,18 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "3.2.6", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async": { + "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT", @@ -4197,6 +4636,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", @@ -4307,6 +4756,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -4543,6 +4999,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -4585,6 +5048,16 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -4609,6 +5082,16 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", @@ -4740,6 +5223,24 @@ "node": ">=0.8.0" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", @@ -5023,6 +5524,21 @@ "node": ">= 0.8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5771,6 +6287,279 @@ "license": "MIT", "optional": true }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", @@ -5889,6 +6678,16 @@ "lru-cache": "6.0.0" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6031,6 +6830,25 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -6114,6 +6932,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -6362,6 +7194,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -6396,6 +7235,55 @@ "node": ">=4" } }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -6678,6 +7566,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rolldown": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.4.tgz", + "integrity": "sha512-rSr7irW0K7QRWzjdJXqZowkcRdDtjRduh43rBltnVKd0VFq839l1lJoDvGJb6gl7+4rTTCrPWu+YfujUL8Ug7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.144.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.4", + "@rolldown/binding-darwin-arm64": "1.2.4", + "@rolldown/binding-darwin-x64": "1.2.4", + "@rolldown/binding-freebsd-x64": "1.2.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.4", + "@rolldown/binding-linux-arm64-gnu": "1.2.4", + "@rolldown/binding-linux-arm64-musl": "1.2.4", + "@rolldown/binding-linux-ppc64-gnu": "1.2.4", + "@rolldown/binding-linux-s390x-gnu": "1.2.4", + "@rolldown/binding-linux-x64-gnu": "1.2.4", + "@rolldown/binding-linux-x64-musl": "1.2.4", + "@rolldown/binding-openharmony-arm64": "1.2.4", + "@rolldown/binding-win32-arm64-msvc": "1.2.4", + "@rolldown/binding-win32-x64-msvc": "1.2.4" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -6938,6 +7859,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -6960,6 +7888,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -6970,6 +7908,13 @@ "node": "*" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -6979,6 +7924,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -7174,6 +8126,50 @@ "license": "MIT", "optional": true }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -7319,6 +8315,174 @@ "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -7383,6 +8547,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/winston": { "version": "3.19.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", diff --git a/kits/storage-resize-images/package.json b/kits/storage-resize-images/package.json index efbd6d18a4..3e4d0cddaf 100644 --- a/kits/storage-resize-images/package.json +++ b/kits/storage-resize-images/package.json @@ -21,7 +21,7 @@ "scripts": { "build": "tsc -b && node -e \"require('fs').copyFileSync('src/placeholder.png','lib/placeholder.png')\"", "clean": "tsc -b --clean", - "test": "echo \"Warning: tests are not implemented for this package\"", + "test": "vitest run", "deploy": "pnpm build && firebase deploy --only functions", "serve": "firebase emulators:start --only functions" }, @@ -35,5 +35,9 @@ "p-queue": "^6.6.2", "sharp": "^0.34.5", "uuid": "^11.0.5" + }, + "devDependencies": { + "@genkit-ai/core": "^1.2.0", + "vitest": "^4.1.10" } } \ No newline at end of file diff --git a/kits/storage-resize-images/tests/config.test.ts b/kits/storage-resize-images/tests/config.test.ts new file mode 100644 index 0000000000..bd6c499587 --- /dev/null +++ b/kits/storage-resize-images/tests/config.test.ts @@ -0,0 +1,120 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Expression } from "firebase-functions/params"; +import { afterEach, describe, expect, test, vi } from "vitest"; + +import { + CONFIG_EXPRESSIONS, + configFromEnv, + validatePathListsFromEnv, +} from "../src/config"; +import { DELETE_IMAGE, resolveResizeImagesConfig } from "../src/export-config"; + +const cel = (value: unknown): string => + value instanceof Expression ? value.toCEL() : String(value); + +describe("configFromEnv", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + test("maps the params a deployed instance sets", () => { + vi.stubEnv("IMG_BUCKET", "demo.appspot.com"); + vi.stubEnv("IMG_SIZES", "200x200,400x400"); + vi.stubEnv("DELETE_ORIGINAL_FILE", "on_success"); + // Firebase writes list params into the environment as JSON. + vi.stubEnv("IMAGE_TYPE", '["jpeg","webp"]'); + vi.stubEnv("RESIZED_IMAGES_PATH", "thumbs"); + vi.stubEnv("CONTENT_FILTER_LEVEL", "BLOCK_ONLY_HIGH"); + vi.stubEnv("FUNCTION_MEMORY", "2048"); + vi.stubEnv("FUNCTION_REGION", "europe-west1"); + + const config = configFromEnv(); + + expect(config.bucket).toBe("demo.appspot.com"); + expect(config.sizes).toBe("200x200,400x400"); + expect(config.deleteOriginal).toBe("on_success"); + expect(config.imageTypes).toEqual(["jpeg", "webp"]); + expect(config.resizedImagesPath).toBe("thumbs"); + expect(config.contentFilterLevel).toBe("BLOCK_ONLY_HIGH"); + expect(config.memory).toBe(2048); + expect(config.region).toBe("europe-west1"); + }); + + test("resolves into the config the handlers use", () => { + vi.stubEnv("IMG_BUCKET", "demo.appspot.com"); + vi.stubEnv("IMG_SIZES", "200x200"); + vi.stubEnv("DELETE_ORIGINAL_FILE", "true"); + vi.stubEnv("IMAGE_TYPE", '["false"]'); + vi.stubEnv("CONTENT_FILTER_LEVEL", "OFF"); + vi.stubEnv("FUNCTION_MEMORY", "1024"); + + const resolved = resolveResizeImagesConfig(configFromEnv()); + + expect(resolved.imageSizes).toEqual(["200x200"]); + expect(resolved.deleteOriginalFile).toBe(DELETE_IMAGE.always); + expect(resolved.contentFilterLevel).toBeNull(); + expect(resolved.memory).toBe("1GiB"); + }); + + test("leaves unset optional strings undefined rather than empty", () => { + vi.stubEnv("IMG_BUCKET", "demo.appspot.com"); + vi.stubEnv("IMAGE_TYPE", '["false"]'); + + const config = configFromEnv(); + + expect(config.resizedImagesPath).toBeUndefined(); + expect(config.failedImagesPath).toBeUndefined(); + expect(config.includePathList).toBeUndefined(); + expect(config.excludePathList).toBeUndefined(); + expect(config.cacheControlHeader).toBeUndefined(); + expect(config.customFilterPrompt).toBeUndefined(); + expect(config.placeholderImagePath).toBeUndefined(); + }); +}); + +describe("validatePathListsFromEnv", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + test("rejects a relative include path before the function deploys", () => { + vi.stubEnv("INCLUDE_PATH_LIST", "relative/path"); + + expect(() => validatePathListsFromEnv()).toThrow("Invalid includePathList"); + }); + + test("rejects a relative exclude path before the function deploys", () => { + vi.stubEnv("EXCLUDE_PATH_LIST", "relative/path"); + + expect(() => validatePathListsFromEnv()).toThrow("Invalid excludePathList"); + }); + + test("accepts absolute paths", () => { + vi.stubEnv("INCLUDE_PATH_LIST", "/users/avatars,/design/pictures"); + vi.stubEnv("EXCLUDE_PATH_LIST", "/users/avatars/thumbs"); + + expect(() => validatePathListsFromEnv()).not.toThrow(); + }); +}); + +describe("CONFIG_EXPRESSIONS", () => { + test("keeps the bucket and memory as params for the discovery manifest", () => { + expect(cel(CONFIG_EXPRESSIONS.bucket)).toBe("{{ params.IMG_BUCKET }}"); + expect(cel(CONFIG_EXPRESSIONS.memory)).toBe("{{ params.FUNCTION_MEMORY }}"); + }); +}); diff --git a/kits/storage-resize-images/tests/content-filter.test.ts b/kits/storage-resize-images/tests/content-filter.test.ts new file mode 100644 index 0000000000..c787bb7c93 --- /dev/null +++ b/kits/storage-resize-images/tests/content-filter.test.ts @@ -0,0 +1,280 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from "node:path"; +import { ValidationError } from "@genkit-ai/core/schema"; +import { beforeEach, describe, expect, test, vi } from "vitest"; + +const generate = vi.fn(); + +vi.mock("genkit", () => ({ + genkit: vi.fn(() => ({ generate })), + z: { + object: vi.fn().mockReturnThis(), + string: vi.fn().mockReturnThis(), + }, +})); + +vi.mock("@genkit-ai/vertexai", () => ({ + default: vi.fn(), + gemini: vi.fn((version: string) => ({ name: `vertexai/${version}` })), +})); + +vi.mock("../src/logs"); + +import { genkit } from "genkit"; +import { checkImageContent } from "../src/content-filter"; +import * as log from "../src/logs"; + +const imagePath = path.join(__dirname, "test-image.png"); +const LOCATION = "us-central1"; + +/** The JSON schema genkit emits for the custom-prompt output shape. */ +const moderationSchema = { + type: "object", + properties: { response: { type: "string" } }, + required: ["response"], + additionalProperties: true, + $schema: "http://json-schema.org/draft-07/schema#", +}; + +describe("checkImageContent", () => { + beforeEach(() => { + vi.clearAllMocks(); + generate.mockResolvedValue({ output: { response: "yes" } }); + }); + + test("returns true when the filter level is off and there is no custom prompt", async () => { + const result = await checkImageContent( + imagePath, + null, + null, + "image/png", + LOCATION + ); + + expect(genkit).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + + test("throws without a function region to reach Vertex AI in", async () => { + await expect( + checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + null, + "image/png", + undefined + ) + ).rejects.toThrow("FUNCTION_REGION is required"); + }); + + test("returns true when the API response is positive", async () => { + const result = await checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + null, + "image/png", + LOCATION + ); + + expect(genkit).toHaveBeenCalled(); + expect(generate).toHaveBeenCalled(); + expect(result).toBe(true); + }); + + test("returns false when a custom prompt answers yes", async () => { + const result = await checkImageContent( + imagePath, + "BLOCK_LOW_AND_ABOVE", + "Is this image containing inappropriate content?", + "image/png", + LOCATION + ); + + expect(log.customFilterBlocked).toHaveBeenCalled(); + expect(result).toBe(false); + }); + + test("returns false when the API throws a blocked finish reason", async () => { + generate.mockRejectedValue({ + detail: { response: { finishReason: "blocked" } }, + }); + + const result = await checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + null, + "image/png", + LOCATION, + 1 + ); + + expect(log.contentFilterBlocked).toHaveBeenCalled(); + expect(result).toBe(false); + }); + + test("rethrows when a generic error occurs", async () => { + generate.mockRejectedValue(new Error("API failure")); + + await expect( + checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + null, + "image/png", + LOCATION, + 1 + ) + ).rejects.toThrow("API failure"); + }); + + test("passes the default prompt and the configured threshold to generate", async () => { + await checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + null, + "image/png", + LOCATION + ); + + const [callArgs] = generate.mock.calls[0]; + expect(callArgs.model?.name ?? callArgs.model).toBe( + "vertexai/gemini-2.5-flash" + ); + expect(callArgs.messages[0].role).toBe("user"); + expect(callArgs.messages[0].content[0].text).toBe( + "Is this image appropriate?" + ); + expect(callArgs.messages[0].content[1].media).toBeDefined(); + expect(callArgs.config.temperature).toBe(0.1); + expect(callArgs.config.maxOutputTokens).toBe(1); + expect(callArgs.config.safetySettings).toEqual( + expect.arrayContaining([ + { + category: "HARM_CATEGORY_HATE_SPEECH", + threshold: "BLOCK_MEDIUM_AND_ABOVE", + }, + ]) + ); + }); + + test("passes a custom prompt and a larger token budget to generate", async () => { + const customPrompt = "Does this image contain violent content?"; + + await checkImageContent( + imagePath, + "BLOCK_MEDIUM_AND_ABOVE", + customPrompt, + "image/png", + LOCATION + ); + + const [callArgs] = generate.mock.calls[0]; + expect(callArgs.messages[0].content[0].text).toContain(customPrompt); + expect(callArgs.config.maxOutputTokens).toBe(100); + }); + + test("applies the requested threshold in both directions", async () => { + generate.mockRejectedValueOnce({ + detail: { response: { finishReason: "blocked" } }, + }); + + expect( + await checkImageContent( + imagePath, + "BLOCK_LOW_AND_ABOVE", + null, + "image/png", + LOCATION + ) + ).toBe(false); + + expect( + await checkImageContent( + imagePath, + "BLOCK_ONLY_HIGH", + null, + "image/png", + LOCATION + ) + ).toBe(true); + }); + + test.each([ + [ + "null content", + { data: null, errors: [{ path: "(root)", message: "must be object" }] }, + ], + [ + "empty object content", + { + data: {}, + errors: [ + { path: "(root)", message: "must have required property 'response'" }, + ], + }, + ], + [ + "a type mismatch", + { + data: { response: 42 }, + errors: [{ path: "response", message: "must be string" }], + }, + ], + ])( + "blocks when genkit rejects the moderation schema with %s", + async (_desc, details) => { + // A schema failure means the model produced no usable verdict, which on + // borderline imagery is almost always an input-side safety refusal. + // Failing open is worse than a false-positive block. + generate.mockRejectedValue( + new ValidationError({ ...details, schema: moderationSchema }) + ); + + const result = await checkImageContent( + imagePath, + "BLOCK_LOW_AND_ABOVE", + "Is this image inappropriate?", + "image/png", + LOCATION + ); + + expect(result).toBe(false); + expect(log.contentFilterBlocked).toHaveBeenCalled(); + // A deterministic refusal must not burn retries. + expect(generate).toHaveBeenCalledTimes(1); + } + ); + + test("retries and rethrows errors that are not schema refusals", async () => { + generate.mockRejectedValue(new Error("ECONNRESET")); + + await expect( + checkImageContent( + imagePath, + "BLOCK_LOW_AND_ABOVE", + "prompt", + "image/png", + LOCATION, + 3 + ) + ).rejects.toThrow("ECONNRESET"); + + expect(generate).toHaveBeenCalledTimes(3); + expect(log.contentFilterBlocked).not.toHaveBeenCalled(); + }, 30000); +}); diff --git a/kits/storage-resize-images/tests/convert-image.test.ts b/kits/storage-resize-images/tests/convert-image.test.ts new file mode 100644 index 0000000000..39cb0c436c --- /dev/null +++ b/kits/storage-resize-images/tests/convert-image.test.ts @@ -0,0 +1,85 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from "node:fs"; +import * as path from "node:path"; +import sharp from "sharp"; +import { beforeAll, describe, expect, test } from "vitest"; + +import { resolveResizeImagesConfig } from "../src/export-config"; +import { convertType } from "../src/util"; + +const config = resolveResizeImagesConfig({ + bucket: "extensions-testing.appspot.com", + sizes: "200x200", + imageTypes: "jpeg", +}); + +const fixture = (name: string) => fs.readFileSync(path.join(__dirname, name)); + +const formatOf = async (buffer: Buffer) => + (await sharp(buffer).metadata()).format; + +let bufferJPG: Buffer; +let bufferPNG: Buffer; +let bufferGIF: Buffer; + +beforeAll(() => { + bufferJPG = fixture("test-image.jpeg"); + bufferPNG = fixture("test-image.png"); + bufferGIF = fixture("test-image.gif"); +}); + +describe("convertType", () => { + test.each([ + ["png", () => bufferJPG, "png"], + ["jpeg", () => bufferPNG, "jpeg"], + ["webp", () => bufferPNG, "webp"], + ["tiff", () => bufferPNG, "tiff"], + ["gif", () => bufferGIF, "gif"], + ])("converts to %s image type", async (format, source, expected) => { + const buffer = await convertType( + source(), + format, + config.outputOptions, + config.animated + ); + + expect(await formatOf(buffer)).toBe(expected); + }); + + test("remains jpeg image type when the target type is not supported", async () => { + const buffer = await convertType( + bufferJPG, + "raw", + config.outputOptions, + config.animated + ); + + expect(await formatOf(buffer)).toBe("jpeg"); + }); + + test("remains gif image type when the target type is not supported", async () => { + const buffer = await convertType( + bufferGIF, + "raw", + config.outputOptions, + config.animated + ); + + expect(await formatOf(buffer)).toBe("gif"); + }); +}); diff --git a/kits/storage-resize-images/tests/export-config.test.ts b/kits/storage-resize-images/tests/export-config.test.ts new file mode 100644 index 0000000000..a27757d0dc --- /dev/null +++ b/kits/storage-resize-images/tests/export-config.test.ts @@ -0,0 +1,136 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, test } from "vitest"; + +import { + convertHarmBlockThreshold, + DELETE_IMAGE, + resolveResizeImagesConfig, + validateAbsolutePathList, +} from "../src/export-config"; + +const base = { bucket: "extensions-testing.appspot.com", sizes: "200x200" }; + +describe("resolveResizeImagesConfig", () => { + test("applies defaults for optional fields", () => { + const resolved = resolveResizeImagesConfig(base); + + expect(resolved).toMatchObject({ + bucket: "extensions-testing.appspot.com", + imageSizes: ["200x200"], + deleteOriginalFile: DELETE_IMAGE.never, + makePublic: false, + imageTypes: ["false"], + sharpOptions: "{}", + animated: true, + memory: "1GiB", + regenerateToken: true, + contentFilterLevel: null, + customFilterPrompt: null, + placeholderImagePath: null, + }); + }); + + test("splits comma-separated sizes and image types", () => { + const resolved = resolveResizeImagesConfig({ + ...base, + sizes: "200x200,400x400", + imageTypes: "jpeg,webp", + }); + + expect(resolved.imageSizes).toEqual(["200x200", "400x400"]); + expect(resolved.imageTypes).toEqual(["jpeg", "webp"]); + }); + + test.each([ + ["true", DELETE_IMAGE.always], + [true, DELETE_IMAGE.always], + ["false", DELETE_IMAGE.never], + [false, DELETE_IMAGE.never], + [undefined, DELETE_IMAGE.never], + ["on_success", DELETE_IMAGE.onSuccess], + ] as const)("maps deleteOriginal %s", (deleteOriginal, expected) => { + expect( + resolveResizeImagesConfig({ ...base, deleteOriginal }).deleteOriginalFile + ).toBe(expected); + }); + + test("maps the memory param onto a function memory option", () => { + expect(resolveResizeImagesConfig({ ...base, memory: 512 }).memory).toBe( + "512MiB" + ); + expect(resolveResizeImagesConfig({ ...base, memory: 8192 }).memory).toBe( + "8GiB" + ); + }); + + test("treats animated sharp options as animated even when the param is off", () => { + expect( + resolveResizeImagesConfig({ + ...base, + isAnimated: false, + sharpOptions: '{"animated":true}', + }).animated + ).toBe(true); + expect( + resolveResizeImagesConfig({ ...base, isAnimated: false }).animated + ).toBe(false); + }); + + test("rejects a path list that is not absolute", () => { + expect(() => + resolveResizeImagesConfig({ ...base, includePathList: "relative/path" }) + ).toThrow("Invalid includePathList"); + expect(() => + resolveResizeImagesConfig({ ...base, excludePathList: "relative/path" }) + ).toThrow("Invalid excludePathList"); + }); +}); + +describe("validateAbsolutePathList", () => { + test("accepts a comma-separated list of absolute paths", () => { + expect( + validateAbsolutePathList( + "/users/avatars,/design/pictures", + "includePathList" + ) + ).toEqual(["/users/avatars", "/design/pictures"]); + }); + + test("treats an empty value as unset", () => { + expect(validateAbsolutePathList("", "includePathList")).toBeUndefined(); + expect( + validateAbsolutePathList(undefined, "includePathList") + ).toBeUndefined(); + }); +}); + +describe("convertHarmBlockThreshold", () => { + test("maps OFF to no filtering", () => { + expect(convertHarmBlockThreshold("OFF")).toBeNull(); + expect(convertHarmBlockThreshold(undefined)).toBeNull(); + }); + + test("passes the Vertex AI thresholds through", () => { + expect(convertHarmBlockThreshold("BLOCK_ONLY_HIGH")).toBe( + "BLOCK_ONLY_HIGH" + ); + expect(convertHarmBlockThreshold("BLOCK_LOW_AND_ABOVE")).toBe( + "BLOCK_LOW_AND_ABOVE" + ); + }); +}); diff --git a/kits/storage-resize-images/tests/file-operations.test.ts b/kits/storage-resize-images/tests/file-operations.test.ts new file mode 100644 index 0000000000..1a82e549b7 --- /dev/null +++ b/kits/storage-resize-images/tests/file-operations.test.ts @@ -0,0 +1,131 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from "node:path"; +import type { Bucket } from "@google-cloud/storage"; +import { beforeEach, describe, expect, test, vi } from "vitest"; + +vi.mock("../src/logs"); + +import { + type ResizeImagesConfig, + resolveResizeImagesConfig, +} from "../src/export-config"; +import { handleFailedImage } from "../src/file-operations"; +import * as logs from "../src/logs"; +import { + countNegativeTraversals, + type StorageObjectMetadata, +} from "../src/util"; + +const object = { + bucket: "test-bucket", + name: "users/uid1/images/photo.jpg", + contentType: "image/jpeg", +} as StorageObjectMetadata; + +function makeConfig(overrides: Partial = {}) { + return resolveResizeImagesConfig({ + bucket: "extensions-testing.appspot.com", + sizes: "200x200", + ...overrides, + }); +} + +function fakeBucket() { + const upload = vi.fn().mockResolvedValue([{}]); + return { upload, bucket: { upload } as unknown as Bucket }; +} + +const run = ( + failedImagesPath: string | undefined, + contentFilterFailed = false +) => { + const { upload, bucket } = fakeBucket(); + return handleFailedImage( + bucket, + "/tmp/local.jpg", + object, + path.parse(object.name), + contentFilterFailed, + makeConfig({ failedImagesPath }) + ).then(() => upload); +}; + +describe("countNegativeTraversals", () => { + test("is non-zero for a path that walks up a directory", () => { + // Matches do not overlap, so consecutive hops share a slash and count + // once. Callers only branch on zero versus non-zero. + expect(countNegativeTraversals("images/../config.json")).toBe(1); + expect(countNegativeTraversals("images/../../config.json")).toBe(1); + expect(countNegativeTraversals("images/thumbs")).toBe(0); + }); +}); + +describe("handleFailedImage", () => { + beforeEach(() => vi.clearAllMocks()); + + test("does nothing when no failed path is configured", async () => { + expect(await run(undefined)).not.toHaveBeenCalled(); + }); + + test("uploads the original under the failed path", async () => { + const upload = await run("failed"); + + expect(upload).toHaveBeenCalledWith("/tmp/local.jpg", { + destination: "users/uid1/images/failed/photo.jpg", + metadata: { metadata: { resizeFailed: "true" } }, + }); + }); + + test("flags images the content filter rejected", async () => { + const upload = await run("failed", true); + + expect(upload).toHaveBeenCalledWith("/tmp/local.jpg", { + destination: "users/uid1/images/failed/photo.jpg", + metadata: { + metadata: { resizeFailed: "true", contentFilterFailed: "true" }, + }, + }); + }); + + test("refuses a failed path that traverses out of the original directory", async () => { + const upload = await run("../../.."); + + expect(upload).not.toHaveBeenCalled(); + expect(logs.invalidFailedResizePath).toHaveBeenCalled(); + }); + + test("refuses a single parent-directory hop", async () => { + // No "/../" to count, so this only stays inside the original prefix + // because the normalized destination is checked as well. + const upload = await run(".."); + + expect(upload).not.toHaveBeenCalled(); + expect(logs.invalidFailedResizePath).toHaveBeenCalled(); + }); + + test("allows a nested failed path", async () => { + const upload = await run("failed/thumbs"); + + expect(upload).toHaveBeenCalledWith( + "/tmp/local.jpg", + expect.objectContaining({ + destination: "users/uid1/images/failed/thumbs/photo.jpg", + }) + ); + }); +}); diff --git a/kits/storage-resize-images/tests/filters.test.ts b/kits/storage-resize-images/tests/filters.test.ts new file mode 100644 index 0000000000..1d3b59c8bd --- /dev/null +++ b/kits/storage-resize-images/tests/filters.test.ts @@ -0,0 +1,129 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { beforeEach, describe, expect, test, vi } from "vitest"; + +vi.mock("../src/logs"); + +import { + type ResizeImagesConfig, + resolveResizeImagesConfig, +} from "../src/export-config"; +import { shouldResize } from "../src/filters"; +import * as logs from "../src/logs"; +import type { StorageObjectMetadata } from "../src/util"; + +const defaultMetadata = { + bucket: "test-bucket", + name: "path/to/image.jpg", + contentType: "image/jpeg", + metadata: {}, +}; + +function makeConfig(overrides: Partial = {}) { + return resolveResizeImagesConfig({ + bucket: "extensions-testing.appspot.com", + sizes: "200x200", + deleteOriginal: "true", + ...overrides, + }); +} + +function check( + object: Partial, + overrides: Partial = {} +) { + return shouldResize( + { ...defaultMetadata, ...object } as StorageObjectMetadata, + makeConfig(overrides) + ); +} + +describe("shouldResize", () => { + beforeEach(() => vi.clearAllMocks()); + + describe("content type checks", () => { + test.each([ + ["no contentType", undefined, () => logs.noContentType], + ["non-image contentType", "text/plain", () => logs.contentTypeInvalid], + ["unsupported image format", "image/foo", () => logs.unsupportedType], + ])("%s", (_desc, contentType, logFunction) => { + expect(check({ contentType })).toBe(false); + expect(logFunction()).toHaveBeenCalled(); + }); + }); + + test("gzip", () => { + expect(check({ contentEncoding: "gzip" })).toBe(false); + expect(logs.gzipContentEncoding).toHaveBeenCalled(); + }); + + describe("path validations", () => { + test("returns false if image is outside of allowed paths", () => { + expect(check({}, { includePathList: "/allowed" })).toBe(false); + + const calls = vi.mocked(logs.imageOutsideOfPaths).mock.calls; + expect(calls).toHaveLength(1); + expect(calls[0][0][0]).toBe("/allowed"); + }); + + test("returns false if image is inside of excluded paths", () => { + expect( + check( + { name: "path/not-allowed/image.jpg" }, + { excludePathList: "/path/not-allowed" } + ) + ).toBe(false); + + const calls = vi.mocked(logs.imageInsideOfExcludedPaths).mock.calls; + expect(calls).toHaveLength(1); + expect(calls[0][0][0]).toBe("/path/not-allowed"); + }); + }); + + describe("metadata checks", () => { + test.each([ + [ + "already resized", + { resizedImage: "true" }, + () => logs.imageAlreadyResized, + ], + [ + "resizing failed previously", + { resizeFailed: "true" }, + () => logs.imageFailedAttempt, + ], + ])( + "returns false if image metadata indicates %s", + (_desc, metadata, logFn) => { + expect(check({ metadata })).toBe(false); + expect(logFn()).toHaveBeenCalled(); + } + ); + }); + + test("returns true if all conditions are met", () => { + expect( + check( + { name: "path/allowed/image.jpg" }, + { + includePathList: "/path/allowed", + excludePathList: "/path/not-allowed", + } + ) + ).toBe(true); + }); +}); diff --git a/kits/storage-resize-images/tests/handlers.test.ts b/kits/storage-resize-images/tests/handlers.test.ts new file mode 100644 index 0000000000..102a7218fc --- /dev/null +++ b/kits/storage-resize-images/tests/handlers.test.ts @@ -0,0 +1,273 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from "node:fs"; +import type * as admin from "firebase-admin"; +import { beforeEach, describe, expect, test, vi } from "vitest"; + +vi.mock("node:fs", async (importOriginal) => ({ + ...(await importOriginal()), + copyFileSync: vi.fn(), +})); +vi.mock("../src/filters"); +vi.mock("../src/file-operations"); +vi.mock("../src/content-filter"); +vi.mock("../src/placeholder"); +vi.mock("../src/resize-image"); +vi.mock("../src/events"); +vi.mock("../src/logs"); + +import { checkImageContent } from "../src/content-filter"; +import { + type ResizeImagesConfig, + resolveResizeImagesConfig, +} from "../src/export-config"; +import { + deleteRemoteFile, + downloadOriginalFile, + handleFailedImage, +} from "../src/file-operations"; +import { shouldResize } from "../src/filters"; +import { + generateResizedImageHandler, + type HandlerContext, +} from "../src/handlers"; +import * as logs from "../src/logs"; +import { replacePlaceholder } from "../src/placeholder"; +import { resizeImages } from "../src/resize-image"; +import type { StorageObjectMetadata } from "../src/util"; + +const mockObject = { + bucket: "demo-bucket", + name: "images/test.jpg", + contentType: "image/jpeg", +} as StorageObjectMetadata; + +const parsedPathMatcher = expect.objectContaining({ + dir: "images", + base: "test.jpg", + name: "test", + ext: ".jpg", +}); + +const remoteFile = { name: "images/test.jpg" }; + +function makeCtx(configOverrides: Partial = {}) { + const config = resolveResizeImagesConfig({ + bucket: "demo-bucket", + sizes: "200x200", + contentFilterLevel: "BLOCK_MEDIUM_AND_ABOVE", + region: "us-central1", + ...configOverrides, + }); + return { + config, + storage: { + bucket: vi.fn(() => ({})), + } as unknown as admin.storage.Storage, + } satisfies HandlerContext as HandlerContext; +} + +describe("generateResizedImageHandler", () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(shouldResize).mockReturnValue(true); + vi.mocked(downloadOriginalFile).mockResolvedValue([ + "/tmp/test.jpg", + remoteFile as never, + ]); + vi.mocked(checkImageContent).mockResolvedValue(true); + vi.mocked(replacePlaceholder).mockResolvedValue(undefined); + vi.mocked(resizeImages).mockResolvedValue([ + { + status: "fulfilled", + value: { + size: "200x200", + outputFilePath: "images/test_200x200.jpg", + success: true, + }, + }, + ]); + }); + + test("does nothing for an object that should not be resized", async () => { + vi.mocked(shouldResize).mockReturnValue(false); + + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(downloadOriginalFile).not.toHaveBeenCalled(); + expect(resizeImages).not.toHaveBeenCalled(); + }); + + test("routes blocked-by-filter images to the failed-image path", async () => { + vi.mocked(checkImageContent).mockResolvedValue(false); + + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(handleFailedImage).toHaveBeenCalledTimes(1); + expect(handleFailedImage).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg", + mockObject, + parsedPathMatcher, + true, + expect.anything() + ); + expect(fs.copyFileSync).toHaveBeenCalledWith( + "/tmp/test.jpg", + "/tmp/test.jpg-placeholder" + ); + expect(replacePlaceholder).toHaveBeenCalledWith( + "/tmp/test.jpg-placeholder", + expect.anything(), + null + ); + expect(resizeImages).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg-placeholder", + parsedPathMatcher, + mockObject, + expect.anything() + ); + }); + + test("resizes when the content filter passes", async () => { + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(replacePlaceholder).not.toHaveBeenCalled(); + expect(resizeImages).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg", + parsedPathMatcher, + mockObject, + expect.anything() + ); + expect(handleFailedImage).not.toHaveBeenCalled(); + }); + + test("treats filter errors as failures and skips resizing", async () => { + vi.mocked(checkImageContent).mockRejectedValue(new Error("filter boom")); + + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(replacePlaceholder).not.toHaveBeenCalled(); + expect(resizeImages).not.toHaveBeenCalled(); + expect(handleFailedImage).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg", + mockObject, + parsedPathMatcher, + false, + expect.anything() + ); + }); + + test("still routes blocked images to the failed path when the placeholder swap errors", async () => { + vi.mocked(checkImageContent).mockResolvedValue(false); + const swapErr = new Error("swap boom"); + vi.mocked(replacePlaceholder).mockRejectedValue(swapErr); + + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(handleFailedImage).toHaveBeenCalledTimes(1); + expect(handleFailedImage).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg", + mockObject, + parsedPathMatcher, + true, + expect.anything() + ); + expect(logs.placeholderReplaceError).toHaveBeenCalledWith(swapErr); + expect(logs.contentFilterErrored).not.toHaveBeenCalled(); + expect(resizeImages).not.toHaveBeenCalled(); + }); + + test("stores the original when a resize fails", async () => { + vi.mocked(resizeImages).mockResolvedValue([ + { + status: "fulfilled", + value: { + size: "200x200", + outputFilePath: "images/test_200x200.jpg", + success: false, + }, + }, + ]); + + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(handleFailedImage).toHaveBeenCalledWith( + expect.anything(), + "/tmp/test.jpg", + mockObject, + parsedPathMatcher, + false, + expect.anything() + ); + expect(logs.failed).toHaveBeenCalled(); + }); + + test("deletes the original on success only in on_success mode", async () => { + await generateResizedImageHandler( + mockObject, + makeCtx({ deleteOriginal: "on_success" }), + false + ); + + expect(deleteRemoteFile).toHaveBeenCalledWith( + remoteFile, + "images/test.jpg" + ); + }); + + test("keeps the original when a resize fails in on_success mode", async () => { + vi.mocked(resizeImages).mockResolvedValue([ + { status: "rejected", reason: new Error("resize boom") }, + ]); + + await generateResizedImageHandler( + mockObject, + makeCtx({ deleteOriginal: "on_success" }), + false + ); + + expect(deleteRemoteFile).not.toHaveBeenCalled(); + }); + + test("deletes the original on any attempt in always mode", async () => { + vi.mocked(resizeImages).mockResolvedValue([ + { status: "rejected", reason: new Error("resize boom") }, + ]); + + await generateResizedImageHandler( + mockObject, + makeCtx({ deleteOriginal: "true" }), + false + ); + + expect(deleteRemoteFile).toHaveBeenCalledWith( + remoteFile, + "images/test.jpg" + ); + }); + + test("never deletes the original by default", async () => { + await generateResizedImageHandler(mockObject, makeCtx(), false); + + expect(deleteRemoteFile).not.toHaveBeenCalled(); + }); +}); diff --git a/kits/storage-resize-images/tests/lib.test.ts b/kits/storage-resize-images/tests/lib.test.ts new file mode 100644 index 0000000000..b63dafeef3 --- /dev/null +++ b/kits/storage-resize-images/tests/lib.test.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, test, vi } from "vitest"; + +vi.mock("firebase-functions", () => ({ + logger: { + debug: vi.fn(), + error: vi.fn(), + info: vi.fn(), + log: vi.fn(), + warn: vi.fn(), + }, +})); + +vi.mock("firebase-functions/params", () => { + throw new Error("./lib must not import firebase-functions/params"); +}); + +describe("./lib", () => { + test("imports without declaring Firebase params", async () => { + const lib = await import("../src/lib"); + + expect(lib.generateResizedImageHandler).toBeTypeOf("function"); + expect(lib.resolveResizeImagesConfig).toBeTypeOf("function"); + expect(lib.shouldResize).toBeTypeOf("function"); + expect(lib.resize).toBeTypeOf("function"); + }, 15000); +}); diff --git a/kits/storage-resize-images/tests/resize-image.test.ts b/kits/storage-resize-images/tests/resize-image.test.ts new file mode 100644 index 0000000000..435a09d27d --- /dev/null +++ b/kits/storage-resize-images/tests/resize-image.test.ts @@ -0,0 +1,245 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import type { Bucket } from "@google-cloud/storage"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; + +vi.mock("../src/logs"); + +import { + type ResizeImagesConfig, + resolveResizeImagesConfig, +} from "../src/export-config"; +import { + constructMetadata, + getModifiedFilePath, + modifyImage, +} from "../src/resize-image"; +import type { StorageObjectMetadata } from "../src/util"; + +const TEST_IMAGE = path.join(__dirname, "test-image.png"); + +function makeConfig(overrides: Partial = {}) { + return resolveResizeImagesConfig({ + bucket: "extensions-testing.appspot.com", + sizes: "200x200", + ...overrides, + }); +} + +describe("getModifiedFilePath", () => { + test("windows path handling", () => { + const parsedPath = { + ext: ".jpg", + dir: "C:\\Users\\user\\Desktop\\storage-resize-images\\images", + name: "test", + }; + const modifiedFileName = `${parsedPath.name}_200x200${parsedPath.ext}`; + + expect( + getModifiedFilePath(parsedPath.dir, "thumbnails", modifiedFileName) + ).toBe( + "C:/Users/user/Desktop/storage-resize-images/images/thumbnails/test_200x200.jpg" + ); + }); + + test("writes alongside the original when no resized path is set", () => { + expect(getModifiedFilePath("images", undefined, "test_200x200.jpg")).toBe( + "images/test_200x200.jpg" + ); + }); +}); + +describe("constructMetadata", () => { + const objectMetadata = { + bucket: "test-bucket", + name: "images/test.jpg", + contentType: "image/jpeg", + cacheControl: "public, max-age=60", + contentDisposition: "inline; filename*=utf-8''test.jpg", + metadata: { firebaseStorageDownloadTokens: "original-token" }, + } as StorageObjectMetadata; + + test("marks the output as a resized image", () => { + const metadata = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig() + ); + + expect(metadata.metadata).toMatchObject({ resizedImage: "true" }); + expect(metadata.contentType).toBe("image/jpeg"); + }); + + test("prefers the configured cache-control header", () => { + const metadata = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig({ cacheControlHeader: "public, max-age=31536000" }) + ); + + expect(metadata.cacheControl).toBe("public, max-age=31536000"); + }); + + test("falls back to the original cache-control header", () => { + const metadata = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig() + ); + + expect(metadata.cacheControl).toBe("public, max-age=60"); + }); + + test("regenerates the download token unless it is turned off", () => { + const regenerated = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig() + ).metadata as Record; + const kept = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig({ regenerateToken: false }) + ).metadata as Record; + + expect(regenerated.firebaseStorageDownloadTokens).not.toBe( + "original-token" + ); + expect(kept.firebaseStorageDownloadTokens).toBe("original-token"); + }); + + test("rewrites the filename in the content disposition", () => { + const metadata = constructMetadata( + "test_200x200.jpeg", + "image/jpeg", + objectMetadata, + makeConfig() + ); + + expect(metadata.contentDisposition).toBe( + "inline; filename*=utf-8''test_200x200.jpeg" + ); + }); +}); + +describe("modifyImage", () => { + const uploaded: { source: string; destination: string }[] = []; + const makePublic = vi.fn().mockResolvedValue(undefined); + const bucket = { + upload: vi.fn(async (source: string, options: { destination: string }) => { + uploaded.push({ source, destination: options.destination }); + return [{ makePublic }]; + }), + } as unknown as Bucket; + const objectMetadata = { + bucket: "test-bucket", + name: "images/test.png", + contentType: "image/png", + metadata: {}, + } as StorageObjectMetadata; + + beforeEach(() => { + uploaded.length = 0; + vi.clearAllMocks(); + }); + + afterEach(() => { + // modifyImage writes to the OS temp dir and cleans up after itself. + expect(uploaded.every(({ source }) => !fs.existsSync(source))).toBe(true); + }); + + test("uploads the resized image next to the original", async () => { + const result = await modifyImage({ + bucket, + originalFile: TEST_IMAGE, + parsedPath: path.parse("images/test.png"), + contentType: "image/png", + size: "75x75", + objectMetadata, + format: "false", + config: makeConfig(), + }); + + expect(result).toMatchObject({ + size: "75x75", + outputFilePath: "images/test_75x75.png", + success: true, + }); + expect(uploaded[0].destination).toBe("images/test_75x75.png"); + expect(uploaded[0].source.startsWith(os.tmpdir())).toBe(true); + }); + + test("converts the output format and extension when one is configured", async () => { + const result = await modifyImage({ + bucket, + originalFile: TEST_IMAGE, + parsedPath: path.parse("images/test.png"), + contentType: "image/png", + size: "75x75", + objectMetadata, + format: "webp", + config: makeConfig({ resizedImagesPath: "thumbs" }), + }); + + expect(result.outputFilePath).toBe("images/thumbs/test_75x75.webp"); + const [, options] = vi.mocked(bucket.upload).mock.calls[0] as unknown as [ + string, + { metadata: { contentType: string } } + ]; + expect(options.metadata.contentType).toBe("image/webp"); + }); + + test("makes the upload public only when configured", async () => { + await modifyImage({ + bucket, + originalFile: TEST_IMAGE, + parsedPath: path.parse("images/test.png"), + contentType: "image/png", + size: "75x75", + objectMetadata, + format: "false", + config: makeConfig({ makePublic: true }), + }); + + expect(makePublic).toHaveBeenCalledTimes(1); + }); + + test("reports failure instead of throwing when the upload fails", async () => { + vi.mocked(bucket.upload).mockRejectedValueOnce(new Error("upload boom")); + + const result = await modifyImage({ + bucket, + originalFile: TEST_IMAGE, + parsedPath: path.parse("images/test.png"), + contentType: "image/png", + size: "75x75", + objectMetadata, + format: "false", + config: makeConfig(), + }); + + expect(result.success).toBe(false); + }); +}); diff --git a/kits/storage-resize-images/tests/resize.test.ts b/kits/storage-resize-images/tests/resize.test.ts new file mode 100644 index 0000000000..ea9c8750a9 --- /dev/null +++ b/kits/storage-resize-images/tests/resize.test.ts @@ -0,0 +1,91 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from "node:path"; +import sharp from "sharp"; +import { describe, expect, test } from "vitest"; + +import { resolveResizeImagesConfig } from "../src/export-config"; +import { + SUPPORTED_CONTENT_TYPES, + SUPPORTED_IMAGE_CONTENT_TYPE_MAP, +} from "../src/global"; +import { resize } from "../src/resize-image"; + +const TEST_IMAGE = path.join(__dirname, "test-image.png"); + +const config = resolveResizeImagesConfig({ + bucket: "extensions-testing.appspot.com", + sizes: "200x200", + deleteOriginal: "true", +}); + +describe("resize", () => { + test("throws if the wrong delimiter is used for the resize string", () => { + const errorMessage = "height and width are not delimited by a ',' or a 'x'"; + + expect(() => resize("/file/path", "200200", config)).toThrow(errorMessage); + expect(() => resize("/file/path", "200 200", config)).toThrow(errorMessage); + }); + + test("accepts either delimiter", async () => { + for (const size of ["75x75", "75,75"]) { + const metadata = await sharp( + await resize(TEST_IMAGE, size, config) + ).metadata(); + + expect(metadata.width).toBe(75); + expect(metadata.height).toBe(75); + } + }); + + test("resizes the image correctly", async () => { + const metadata = await sharp( + await resize(TEST_IMAGE, "75x75", config) + ).metadata(); + + expect(metadata.width).toBe(75); + expect(metadata.height).toBe(75); + }); + + test("does not enlarge an image smaller than the requested size", async () => { + const original = await sharp(TEST_IMAGE).metadata(); + const metadata = await sharp( + await resize(TEST_IMAGE, "5000x5000", config) + ).metadata(); + + expect(metadata.width).toBe(original.width); + expect(metadata.height).toBe(original.height); + }); + + test("image types supported", () => { + expect(SUPPORTED_CONTENT_TYPES).toEqual( + expect.arrayContaining([ + "image/jpeg", + "image/png", + "image/tiff", + "image/webp", + ]) + ); + expect(SUPPORTED_IMAGE_CONTENT_TYPE_MAP).toMatchObject({ + jpg: "image/jpeg", + jpeg: "image/jpeg", + png: "image/png", + tiff: "image/tiff", + webp: "image/webp", + }); + }); +}); diff --git a/kits/storage-resize-images/tests/retry-queue.test.ts b/kits/storage-resize-images/tests/retry-queue.test.ts new file mode 100644 index 0000000000..500ae57803 --- /dev/null +++ b/kits/storage-resize-images/tests/retry-queue.test.ts @@ -0,0 +1,161 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import PQueue from "p-queue"; +import { describe, expect, test, vi } from "vitest"; + +import { GLOBAL_RETRY_QUEUE } from "../src/global"; + +describe("retry queue", () => { + test("processes tasks in order of priority", async () => { + const queue = new PQueue({ concurrency: 1, autoStart: false }); + const executionOrder: number[] = []; + const task = (id: number) => + vi.fn(async () => { + executionOrder.push(id); + return `result${id}`; + }); + const [task1, task2, task3] = [task(1), task(2), task(3)]; + + const promises = [ + queue.add(task2, { priority: 2 }), + queue.add(task3, { priority: 1 }), + queue.add(task1, { priority: 3 }), + ]; + + queue.start(); + await Promise.all(promises); + + expect(executionOrder).toEqual([1, 2, 3]); + expect(task1).toHaveBeenCalledTimes(1); + expect(task2).toHaveBeenCalledTimes(1); + expect(task3).toHaveBeenCalledTimes(1); + }); + + test("handles task failures correctly", async () => { + const queue = new PQueue({ concurrency: 3, autoStart: false }); + const successTask = vi.fn().mockResolvedValue("success"); + const failureTask = vi.fn().mockRejectedValue(new Error("Task failed")); + + const successPromise = queue.add(successTask, { priority: 2 }); + const failurePromise = queue.add(failureTask, { priority: 1 }); + + queue.start(); + + await expect(successPromise).resolves.toBe("success"); + await expect(failurePromise).rejects.toThrow("Task failed"); + expect(successTask).toHaveBeenCalledTimes(1); + expect(failureTask).toHaveBeenCalledTimes(1); + }); + + test("respects the concurrency limit", async () => { + const queue = new PQueue({ concurrency: 3, autoStart: false }); + let concurrentCount = 0; + let maxConcurrentCount = 0; + const createTask = (delay: number) => async () => { + concurrentCount++; + maxConcurrentCount = Math.max(maxConcurrentCount, concurrentCount); + await new Promise((resolve) => setTimeout(resolve, delay)); + concurrentCount--; + return delay; + }; + + const promises = Array.from({ length: 10 }, (_, i) => + queue.add(createTask(10), { priority: i + 1 }) + ); + + queue.start(); + await Promise.all(promises); + + expect(maxConcurrentCount).toBeLessThanOrEqual(3); + }); + + test("continues processing the queue after a task completes", async () => { + const queue = new PQueue({ concurrency: 1, autoStart: false }); + const executionOrder: number[] = []; + const slowTask = async () => { + executionOrder.push(1); + await new Promise((resolve) => setTimeout(resolve, 20)); + return "slow done"; + }; + const fastTask = (id: number) => async () => { + executionOrder.push(id); + return `fast${id} done`; + }; + + const promises = [ + queue.add(slowTask, { priority: 3 }), + queue.add(fastTask(2), { priority: 2 }), + queue.add(fastTask(3), { priority: 1 }), + ]; + + queue.start(); + await Promise.all(promises); + + expect(executionOrder).toEqual([1, 2, 3]); + }); + + test("handles an empty queue gracefully", () => { + const queue = new PQueue({ concurrency: 3 }); + + expect(() => queue.start()).not.toThrow(); + }); + + test("runs tasks of equal priority in the order they were added", async () => { + const queue = new PQueue({ concurrency: 1, autoStart: false }); + const executionOrder: number[] = []; + + const promises = Array.from({ length: 5 }, (_, i) => + queue.add( + async () => { + executionOrder.push(i + 1); + return `result${i + 1}`; + }, + { priority: 1 } + ) + ); + + queue.start(); + await Promise.all(promises); + + expect(executionOrder).toEqual([1, 2, 3, 4, 5]); + }); + + test("handles a large number of tasks", async () => { + const queue = new PQueue({ concurrency: 3, autoStart: false }); + const taskCount = 50; + const completedTasks: number[] = []; + + const promises = Array.from({ length: taskCount }, (_, i) => + queue.add( + async () => { + completedTasks.push(i); + return i; + }, + { priority: i } + ) + ); + + queue.start(); + await Promise.all(promises); + + expect(completedTasks).toHaveLength(taskCount); + }); + + test("the shared content-filter queue caps concurrency at three", () => { + expect(GLOBAL_RETRY_QUEUE.concurrency).toBe(3); + }); +}); diff --git a/kits/storage-resize-images/tests/test-image.gif b/kits/storage-resize-images/tests/test-image.gif new file mode 100644 index 0000000000000000000000000000000000000000..71dfb6517ecc6343d20d2995dcc9ced203948e84 GIT binary patch literal 207266 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 z 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 G-Qx{0pd-To literal 0 HcmV?d00001 diff --git a/kits/storage-resize-images/tests/test-image.png b/kits/storage-resize-images/tests/test-image.png new file mode 100644 index 0000000000000000000000000000000000000000..73ad235b221b998f469b712df5ad31e6ee715f9a GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^DImFO9eZ5Df;BO!Wbbd6u_|uoyQy+%lml zfz4o!SdhROhPKO2TuqV(3Zgt54VWeTxHUP_7!GGDvL56~u+SaxnkvorrZApdbMOK% P^cg%|{an^LB{Ts50BeOT literal 0 HcmV?d00001 diff --git a/kits/storage-resize-images/tests/util.test.ts b/kits/storage-resize-images/tests/util.test.ts new file mode 100644 index 0000000000..5d4084a8b9 --- /dev/null +++ b/kits/storage-resize-images/tests/util.test.ts @@ -0,0 +1,121 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, test } from "vitest"; + +import { convertPathToPosix, startsWithArray } from "../src/util"; + +const imagePath = ["/test/picture"]; + +describe("startsWithArray", () => { + test("allowed paths", () => { + const allowed = ["/test/picture", "/test/picture/directory"]; + + for (const path of allowed) { + expect(startsWithArray(imagePath, path)).toBe(true); + } + }); + + test("blocked paths", () => { + const notAllowed = [ + "/test", + "/test/pict", + "/test/pictures", + "/test/picturesssssss", + ]; + + for (const path of notAllowed) { + expect(startsWithArray(imagePath, path)).toBe(false); + } + }); + + test("can handle allowed globbed paths", () => { + const imagePaths = ["/test/picture", "/test/*/picture"]; + const allowed = [ + "/test/picture", + "/test/something/picture", + "/test/folder1/folder2/picture", + ]; + + for (const path of allowed) { + expect(startsWithArray(imagePaths, path)).toBe(true); + } + }); + + test("can handle not allowed globbed paths", () => { + const imagePaths = ["/test/picture", "/test/*/picture"]; + const notAllowed = ["/test/*/pictures", "/test/*/folder2/pictures"]; + + for (const path of notAllowed) { + expect(startsWithArray(imagePaths, path)).toBe(false); + } + }); + + test("can handle '+' when replacing '*' in globbed paths", () => { + const allowed = ["/test/picture", "/test/*/picture"]; + const imagePaths = ["/test/picture", "/test/+/picture"]; + + for (const path of imagePaths) { + expect(startsWithArray(allowed, path)).toBe(true); + } + }); +}); + +describe("convertPathToPosix", () => { + const windowsPaths = [ + "C:\\Users\\test\\image.jpg", + "D:\\Users\\test\\image.jpg", + "E:\\Users\\test\\image.jpg", + "Z:\\Users\\test\\image.jpg", + "C:\\Users\\test:user\\image.jpg", + ]; + + test("converts windows path to posix without drive", () => { + const expected = [ + "/Users/test/image.jpg", + "/Users/test/image.jpg", + "/Users/test/image.jpg", + "/Users/test/image.jpg", + "/Users/test:user/image.jpg", + ]; + + windowsPaths.forEach((windowsPath, index) => { + expect(convertPathToPosix(windowsPath, true)).toBe(expected[index]); + }); + }); + + test("converts windows path to posix with drive", () => { + const expected = [ + "C:/Users/test/image.jpg", + "D:/Users/test/image.jpg", + "E:/Users/test/image.jpg", + "Z:/Users/test/image.jpg", + "C:/Users/test:user/image.jpg", + ]; + + windowsPaths.forEach((windowsPath, index) => { + expect(convertPathToPosix(windowsPath, false)).toBe(expected[index]); + }); + }); + + test("converts posix path to posix (no change)", () => { + const posixPaths = ["/Users/test/image.jpg", "/Users/test:user/image.jpg"]; + + for (const posixPath of posixPaths) { + expect(convertPathToPosix(posixPath)).toBe(posixPath); + } + }); +}); From 4245b14f3689038613a6745c4ed3f410581adb2c Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Tue, 18 Aug 2026 23:15:55 +0100 Subject: [PATCH 2/2] test(storage-resize-images): add emulator e2e tests Ports the extension's e2e suite. A small app under tests/emulator/app loads the built kit as a functions codebase, so the Storage trigger runs for real against the emulator and the tests assert on the files it writes. The app carries its own package.json because the Functions emulator rejects the kit's `engines: ">=22"` and wants an exact major. `pnpm test` still runs only the unit tests; `pnpm test:emulator` runs these. --- kits/.gitignore | 2 + kits/storage-resize-images/firebase.json | 12 +++ kits/storage-resize-images/package.json | 1 + .../tests/emulator/app/.env | 8 ++ .../tests/emulator/app/index.js | 17 ++++ .../tests/emulator/app/package.json | 6 ++ .../tests/emulator/e2e.test.ts | 96 ++++++++++++++++++ .../tests/emulator/storage.rules | 6 ++ .../tests/not-an-image.jpeg | 0 .../storage-resize-images/tests/test-img.jfif | Bin 0 -> 3740 bytes kits/storage-resize-images/tests/test-jpg.jpg | Bin 0 -> 3164 bytes kits/storage-resize-images/vitest.config.ts | 23 +++++ .../vitest.emulator.config.ts | 28 +++++ 13 files changed, 199 insertions(+) create mode 100644 kits/storage-resize-images/firebase.json create mode 100644 kits/storage-resize-images/tests/emulator/app/.env create mode 100644 kits/storage-resize-images/tests/emulator/app/index.js create mode 100644 kits/storage-resize-images/tests/emulator/app/package.json create mode 100644 kits/storage-resize-images/tests/emulator/e2e.test.ts create mode 100644 kits/storage-resize-images/tests/emulator/storage.rules create mode 100644 kits/storage-resize-images/tests/not-an-image.jpeg create mode 100644 kits/storage-resize-images/tests/test-img.jfif create mode 100644 kits/storage-resize-images/tests/test-jpg.jpg create mode 100644 kits/storage-resize-images/vitest.config.ts create mode 100644 kits/storage-resize-images/vitest.emulator.config.ts diff --git a/kits/.gitignore b/kits/.gitignore index a0f26bba1a..4d9946868c 100644 --- a/kits/.gitignore +++ b/kits/.gitignore @@ -9,6 +9,8 @@ dist/ # Env / secrets .env .env.* +# Emulator test apps commit their params: demo values, never secrets. +!*/tests/emulator/app/.env # Test / coverage coverage/ diff --git a/kits/storage-resize-images/firebase.json b/kits/storage-resize-images/firebase.json new file mode 100644 index 0000000000..33e58a4362 --- /dev/null +++ b/kits/storage-resize-images/firebase.json @@ -0,0 +1,12 @@ +{ + "functions": [ + { "source": "tests/emulator/app", "codebase": "storage-resize-images" } + ], + "storage": { "rules": "tests/emulator/storage.rules" }, + "emulators": { + "storage": { "port": 9199 }, + "functions": { "port": 5001 }, + "eventarc": { "port": 9299 }, + "ui": { "enabled": false } + } +} diff --git a/kits/storage-resize-images/package.json b/kits/storage-resize-images/package.json index 3e4d0cddaf..da51a4b56c 100644 --- a/kits/storage-resize-images/package.json +++ b/kits/storage-resize-images/package.json @@ -22,6 +22,7 @@ "build": "tsc -b && node -e \"require('fs').copyFileSync('src/placeholder.png','lib/placeholder.png')\"", "clean": "tsc -b --clean", "test": "vitest run", + "test:emulator": "npm run build && firebase emulators:exec --only functions,storage --project demo-test \"vitest run --config vitest.emulator.config.ts\"", "deploy": "pnpm build && firebase deploy --only functions", "serve": "firebase emulators:start --only functions" }, diff --git a/kits/storage-resize-images/tests/emulator/app/.env b/kits/storage-resize-images/tests/emulator/app/.env new file mode 100644 index 0000000000..e69791b9fa --- /dev/null +++ b/kits/storage-resize-images/tests/emulator/app/.env @@ -0,0 +1,8 @@ +IMG_BUCKET=demo-test.appspot.com +IMG_SIZES=200x200 +DELETE_ORIGINAL_FILE=false +IMAGE_TYPE=["false"] +CONTENT_FILTER_LEVEL=OFF +FUNCTION_MEMORY=1024 +RESIZED_IMAGES_PATH=thumbs +FAILED_IMAGES_PATH=failed diff --git a/kits/storage-resize-images/tests/emulator/app/index.js b/kits/storage-resize-images/tests/emulator/app/index.js new file mode 100644 index 0000000000..66310fcfb8 --- /dev/null +++ b/kits/storage-resize-images/tests/emulator/app/index.js @@ -0,0 +1,17 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = require("../../../lib/index.js"); diff --git a/kits/storage-resize-images/tests/emulator/app/package.json b/kits/storage-resize-images/tests/emulator/app/package.json new file mode 100644 index 0000000000..d65f0756b4 --- /dev/null +++ b/kits/storage-resize-images/tests/emulator/app/package.json @@ -0,0 +1,6 @@ +{ + "name": "storage-resize-images-emulator-app", + "private": true, + "main": "index.js", + "engines": { "node": "24" } +} diff --git a/kits/storage-resize-images/tests/emulator/e2e.test.ts b/kits/storage-resize-images/tests/emulator/e2e.test.ts new file mode 100644 index 0000000000..12354a56c6 --- /dev/null +++ b/kits/storage-resize-images/tests/emulator/e2e.test.ts @@ -0,0 +1,96 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from "node:path"; +import * as admin from "firebase-admin"; +import { beforeAll, describe, expect, test } from "vitest"; + +process.env.FIREBASE_STORAGE_EMULATOR_HOST = "127.0.0.1:9199"; +process.env.STORAGE_EMULATOR_HOST = "http://127.0.0.1:9199"; +process.env.GOOGLE_CLOUD_PROJECT = "demo-test"; + +const BUCKET = "demo-test.appspot.com"; +const RESIZED_PATH = "thumbs"; +const FAILED_PATH = "failed"; +const SIZE = "200x200"; + +let storage: admin.storage.Storage; + +const fixture = (name: string) => path.join(__dirname, "..", name); + +/** Polls until the trigger has written the file, or gives up. */ +async function waitForFile( + filePath: string, + timeout = 30_000 +): Promise { + const deadline = Date.now() + timeout; + while (Date.now() < deadline) { + const [exists] = await storage.bucket(BUCKET).file(filePath).exists(); + if (exists) return true; + await new Promise((resolve) => setTimeout(resolve, 500)); + } + return false; +} + +describe("generateResizedImage in the emulator", () => { + beforeAll(async () => { + if (!admin.apps.length) { + admin.initializeApp({ projectId: "demo-test", storageBucket: BUCKET }); + } + storage = admin.storage(); + + const bucket = storage.bucket(BUCKET); + await bucket.upload(fixture("test-image.jpeg"), { + destination: "test-image.jpeg", + metadata: { contentType: "image/jpeg" }, + }); + await bucket.upload(fixture("not-an-image.jpeg"), { + destination: "not-an-image.jpeg", + metadata: { contentType: "image/jpeg" }, + }); + await bucket.upload(fixture("test-img.jfif"), { + destination: "test-img.jfif", + metadata: { contentType: "image/jpeg" }, + }); + }); + + test("resizes test-image.jpeg", async () => { + expect(await waitForFile(`${RESIZED_PATH}/test-image_${SIZE}.jpeg`)).toBe( + true + ); + }); + + test("copies a file that is not an image to the failed directory", async () => { + expect(await waitForFile(`${FAILED_PATH}/not-an-image.jpeg`)).toBe(true); + }); + + test("resizes test-img.jfif", async () => { + expect(await waitForFile(`${RESIZED_PATH}/test-img_${SIZE}.jfif`)).toBe( + true + ); + }); + + test("resizes an image uploaded with a jpg content type", async () => { + await storage.bucket(BUCKET).upload(fixture("test-jpg.jpg"), { + destination: "test-jpg.jpg", + metadata: { contentType: "image/jpg" }, + }); + + expect(await waitForFile(`${RESIZED_PATH}/test-jpg_${SIZE}.jpg`)).toBe( + true + ); + }); +}); diff --git a/kits/storage-resize-images/tests/emulator/storage.rules b/kits/storage-resize-images/tests/emulator/storage.rules new file mode 100644 index 0000000000..10ee8060b6 --- /dev/null +++ b/kits/storage-resize-images/tests/emulator/storage.rules @@ -0,0 +1,6 @@ +rules_version = '2'; +service firebase.storage { + match /b/{bucket}/o { + match /{allPaths=**} { allow read, write: if true; } + } +} diff --git a/kits/storage-resize-images/tests/not-an-image.jpeg b/kits/storage-resize-images/tests/not-an-image.jpeg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kits/storage-resize-images/tests/test-img.jfif b/kits/storage-resize-images/tests/test-img.jfif new file mode 100644 index 0000000000000000000000000000000000000000..46e576e9050fd5ad9c44f89239fd6004301a9f2b GIT binary patch literal 3740 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 literal 0 HcmV?d00001 diff --git a/kits/storage-resize-images/tests/test-jpg.jpg b/kits/storage-resize-images/tests/test-jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad6a79056fa23c9f72427f55178388dfa8304b67 GIT binary patch literal 3164 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 aB}v>jyxR3Qt5)J!A