diff --git a/package.json b/package.json index fdebcab..05982df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lambdatest/smartui-cli", - "version": "4.1.80", + "version": "5.0.0-unified.3", "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest", "files": [ "dist/**/*" @@ -9,7 +9,10 @@ "build": "tsup", "release": "pnpm run build && pnpm publish --access public --no-git-checks", "release:beta": "pnpm run build && pnpm publish --tag beta --access public --no-git-checks", - "local-build": "pnpm run build && pnpm pack" + "local-build": "pnpm run build && pnpm pack", + "test": "vitest run", + "test:watch": "vitest", + "typecheck:storybook": "tsc -p tsconfig.storybook.json" }, "bin": { "smartui": "./dist/index.cjs" @@ -34,16 +37,27 @@ "@types/which": "^3.0.2", "ajv": "^8.12.0", "ajv-errors": "^3.0.0", + "archiver": "^5.3.1", "axios": "^1.12.0", + "boxen": "^5.1.2", "chalk": "^4.1.2", + "cli-table3": "^0.6.3", "commander": "^11.1.0", "cross-spawn": "^7.0.6", "fastify": "^4.29.1", + "figlet": "^1.7.0", "form-data": "^4.0.4", + "gradient-string": "^2.0.2", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "jsdom": "^21.1.0", "json-stringify-safe": "^5.0.1", "listr2": "^7.0.1", + "log-symbols": "^4.1.0", "node-cache": "^5.1.2", + "ora": "^5.4.1", "postcss": "^8.5.6", + "puppeteer": "^19.5.2", "sharp": "^0.33.4", "uuid": "^11.0.3", "which": "^4.0.0", @@ -52,9 +66,24 @@ "overrides": { "simple-swizzle": "0.2.2" }, + "pnpm": { + "onlyBuiltDependencies": [ + "@playwright/browser-chromium", + "@playwright/browser-firefox", + "@playwright/browser-webkit", + "esbuild", + "puppeteer", + "sharp" + ] + }, "devDependencies": { + "@types/archiver": "^5.3.4", "find-free-port": "^2.0.0", + "tsup": "^8.5.1", "typescript": "^5.3.2", - "tsup": "^8.5.1" + "vitest": "^2.1.9" + }, + "engines": { + "node": ">=20.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b49e672..08e2bea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,21 +8,27 @@ importers: .: dependencies: + '@lambdatest/node-tunnel': + specifier: ^4.0.9 + version: 4.0.11 '@playwright/browser-chromium': - specifier: ^1.47.2 - version: 1.47.2 + specifier: ~1.54.1 + version: 1.54.2 '@playwright/browser-firefox': - specifier: ^1.47.2 - version: 1.47.2 + specifier: ~1.54.1 + version: 1.54.2 '@playwright/browser-webkit': - specifier: ^1.47.2 - version: 1.47.2 + specifier: ~1.54.1 + version: 1.54.2 '@playwright/test': - specifier: ^1.47.2 - version: 1.47.2 + specifier: ~1.54.1 + version: 1.54.2 '@types/cross-spawn': specifier: ^6.0.4 version: 6.0.5 + '@types/json-stringify-safe': + specifier: ^5.0.3 + version: 5.0.3 '@types/node': specifier: ^20.8.9 version: 20.9.0 @@ -35,33 +41,75 @@ importers: ajv-errors: specifier: ^3.0.0 version: 3.0.0(ajv@8.12.0) + archiver: + specifier: ^5.3.1 + version: 5.3.2 axios: - specifier: ^1.6.0 - version: 1.6.2 + specifier: ^1.12.0 + version: 1.18.1 + boxen: + specifier: ^5.1.2 + version: 5.1.2 chalk: specifier: ^4.1.2 version: 4.1.2 + cli-table3: + specifier: ^0.6.3 + version: 0.6.5 commander: specifier: ^11.1.0 version: 11.1.0 cross-spawn: - specifier: ^7.0.3 - version: 7.0.3 + specifier: ^7.0.6 + version: 7.0.6 fastify: - specifier: ^4.24.3 - version: 4.24.3 + specifier: ^4.29.1 + version: 4.29.1 + figlet: + specifier: ^1.7.0 + version: 1.11.0 form-data: - specifier: ^4.0.0 - version: 4.0.0 + specifier: ^4.0.4 + version: 4.0.6 + gradient-string: + specifier: ^2.0.2 + version: 2.0.2 + http-proxy-agent: + specifier: ^7.0.0 + version: 7.0.2 + https-proxy-agent: + specifier: ^7.0.0 + version: 7.0.6 + jsdom: + specifier: ^21.1.0 + version: 21.1.2 + json-stringify-safe: + specifier: ^5.0.1 + version: 5.0.1 listr2: specifier: ^7.0.1 version: 7.0.2 + log-symbols: + specifier: ^4.1.0 + version: 4.1.0 + node-cache: + specifier: ^5.1.2 + version: 5.1.2 + ora: + specifier: ^5.4.1 + version: 5.4.1 + postcss: + specifier: ^8.5.6 + version: 8.5.16 + puppeteer: + specifier: ^19.5.2 + version: 19.11.1(typescript@5.3.2) sharp: specifier: ^0.33.4 version: 0.33.4 - tsup: - specifier: ^7.2.0 - version: 7.2.0(typescript@5.3.2) + uuid: + specifier: ^11.0.3 + version: 11.1.1 which: specifier: ^4.0.0 version: 4.0.0 @@ -69,12 +117,32 @@ importers: specifier: ^3.10.0 version: 3.10.0 devDependencies: + '@types/archiver': + specifier: ^5.3.4 + version: 5.3.4 + find-free-port: + specifier: ^2.0.0 + version: 2.0.0 + tsup: + specifier: ^8.5.1 + version: 8.5.1(postcss@8.5.16)(typescript@5.3.2) typescript: specifier: ^5.3.2 version: 5.3.2 + vitest: + specifier: ^2.1.9 + version: 2.1.9(@types/node@20.9.0)(jsdom@21.1.2) packages: + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -89,138 +157,300 @@ packages: '@emnapi/runtime@1.2.0': resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@fastify/ajv-compiler@3.5.0': resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} @@ -262,72 +492,84 @@ packages: engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.2': resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.2': resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.2': resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==} engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.2': resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.2': resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.4': resolution: {integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.4': resolution: {integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.4': resolution: {integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==} engines: {glibc: '>=2.31', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.4': resolution: {integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.4': resolution: {integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.4': resolution: {integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.4': resolution: {integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==} @@ -361,57 +603,277 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.20': resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + '@lambdatest/node-tunnel@4.0.11': + resolution: {integrity: sha512-IPCBUECSLHOsUhhaopMGkcBV3sRrt6w+y+Lfykm3rR9I0xNgjHNOQ73hxawDuN/188aneouWoDxnrOMEDeFpiA==} - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@playwright/browser-chromium@1.47.2': - resolution: {integrity: sha512-tsk9bLcGzIu4k4xI2ixlwDrdJhMqCalUCsSj7TRI8VuvK7cLiJIa5SR0dprKbX+wkku/JMR4EN6g9DMHvfna+Q==} + '@playwright/browser-chromium@1.54.2': + resolution: {integrity: sha512-DqmhKemShLoF3x4LxEnTc0XPlHSedB3grOpokz9nnXkRsdMHIjVjeGz5QyZXWh6wONWNQrLbdD5iU5cb3tRsLg==} engines: {node: '>=18'} - '@playwright/browser-firefox@1.47.2': - resolution: {integrity: sha512-0+APQGDqeTrb7XLCUr13sgTXV04ky121JsxE93JXj6mrEkoXeBqvbHLkXO3xrPUs1O1kL92Bc2eJ87KW2i5Jog==} + '@playwright/browser-firefox@1.54.2': + resolution: {integrity: sha512-I0ZEliCzZq9k5SXQVkYRM9AG0igpa9GcSvjp8xFkSbxQiRYwuEswbwU7DYybjQREkFJ+6XmQ2k7IfmKhjIhUkA==} engines: {node: '>=18'} - '@playwright/browser-webkit@1.47.2': - resolution: {integrity: sha512-NHXueW09Ou26raqzDccUaSUbmiBMY0eonqQVvUbrTRNNRlMA8Vp6lGqZiPy5qo/FvEeQBSsZSCfH/MnathYhdg==} + '@playwright/browser-webkit@1.54.2': + resolution: {integrity: sha512-r8zJRe5NBSvgctXqoiBCN+qlsZdcF6oLRV3lxYUH/gOo8oLXUcZrw4RnH5UNyOlxF3cXiHkJL7zDmN1IgP81Yg==} engines: {node: '>=18'} - '@playwright/test@1.47.2': - resolution: {integrity: sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==} + '@playwright/test@1.54.2': + resolution: {integrity: sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==} engines: {node: '>=18'} hasBin: true + '@puppeteer/browsers@0.5.0': + resolution: {integrity: sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==} + engines: {node: '>=14.1.0'} + hasBin: true + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} + cpu: [x64] + os: [win32] + + '@tootallnate/once@2.0.1': + resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} + engines: {node: '>= 10'} + + '@types/archiver@5.3.4': + resolution: {integrity: sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==} + '@types/cross-spawn@6.0.5': resolution: {integrity: sha512-wsIMP68FvGXk+RaWhraz6Xp4v7sl4qwzHAmtPaJEN2NRTXXI9LtFawUpeTsBNL/pd6QoLStdytCaAyiK7AEd/Q==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-stringify-safe@5.0.3': + resolution: {integrity: sha512-oNOjRxLfPeYbBSQ60maucaFNqbslVOPU4WWs5t/sHvAh6tyo/CThXSG+E24tEzkgh/fzvxyDrYdOJufgeNy1sQ==} + '@types/node@20.9.0': resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==} + '@types/readdir-glob@1.1.5': + resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} + + '@types/tinycolor2@1.4.6': + resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} + '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} '@types/which@3.0.2': resolution: {integrity: sha512-UqCG7NjNyume6e+BHcFkOQOS8of/E18V2z/jTRkiD98YiiryYOFBVvPxqA/8PQCwkn7icKqz/hFflMIRN2HGhQ==} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + adm-zip@0.5.18: + resolution: {integrity: sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==} + engines: {node: '>=12.0'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv-errors@3.0.0: resolution: {integrity: sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==} peerDependencies: @@ -428,10 +890,17 @@ packages: ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-escapes@5.0.0: resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} engines: {node: '>=12'} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} @@ -447,16 +916,24 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} - archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + archiver-utils@3.0.4: + resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} + engines: {node: '>= 10'} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} @@ -468,11 +945,11 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - avvio@8.2.1: - resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==} + avvio@8.4.0: + resolution: {integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==} - axios@1.6.2: - resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==} + axios@1.18.1: + resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -480,46 +957,107 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + brace-expansion@2.1.2: + resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - bundle-require@4.0.2: - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: '>=0.17' + esbuild: '>=0.18' cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chromium-bidi@0.4.7: + resolution: {integrity: sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==} + peerDependencies: + devtools-protocol: '*' + + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -557,21 +1095,63 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + compress-commons@4.1.2: + resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} + engines: {node: '>= 10'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig@8.1.3: + resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} + engines: {node: '>=14'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + + cross-fetch@3.1.5: + resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssstyle@3.0.0: + resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} + engines: {node: '>=14'} + + data-urls@4.0.0: + resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} + engines: {node: '>=14'} + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -581,6 +1161,25 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -589,38 +1188,105 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + devtools-protocol@0.0.1107588: + resolution: {integrity: sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==} + + domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true fast-content-type-parse@1.1.0: resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} @@ -631,45 +1297,56 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - fast-json-stringify@5.9.1: resolution: {integrity: sha512-NMrf+uU9UJnTzfxaumMDXK1NWqtPCfGoM9DYIE+ESlaTQqjlANFBy0VAbsm6FB88Mx0nceyi18zTo5kIEUlzxg==} fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - fast-redact@3.3.0: - resolution: {integrity: sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==} - engines: {node: '>=6'} - fast-uri@2.3.0: resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==} - fastify@4.24.3: - resolution: {integrity: sha512-6HHJ+R2x2LS3y1PqxnwEIjOTZxFl+8h4kSC/TuDPXtA+v2JnV9yEtOsNSKK1RMD7sIR2y1ZsA4BEFaid/cK5pg==} + fastify@4.29.1: + resolution: {integrity: sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==} - fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true fecha@4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + figlet@1.11.0: + resolution: {integrity: sha512-EEx3OS/l2bFqcUNN2NM9FPJp8vAMrgbCxsbl2hbcJNNxOEwVe3mEzrhan7TbJQViZa8mMqhihlbCaqD+LyYKTQ==} + engines: {node: '>= 17.0.0'} + hasBin: true + + find-free-port@2.0.0: + resolution: {integrity: sha512-J1j8gfEVf5FN4PR5w5wrZZ7NYs2IvqsHcd03cAeQx3Ec/mo+lKceaVNhpsRKoZpZKbId88o8qh+dwUwzBV6WCg==} - find-my-way@7.7.0: - resolution: {integrity: sha512-+SrHpvQ52Q6W9f3wJoJBbAQULJuNEEQwBvlvYwACDhBTLOTMiQ0HYWh4+vC3OivGP2ENcTI1oKlFA2OepJNjhQ==} + find-my-way@8.2.2: + resolution: {integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==} engines: {node: '>=14'} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - follow-redirects@1.15.3: - resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -677,14 +1354,17 @@ packages: debug: optional: true - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -698,38 +1378,99 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-port@1.0.0: + resolution: {integrity: sha512-vg59F3kcXBOtcIijwtdAyCxFocyv/fVkGQvw1kVGrxFO1U4SSGkGjrbASg5DN3TVekVle/jltwOjYRnZWc1YdA==} + engines: {node: '>=0.10.0'} + hasBin: true + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gradient-string@2.0.2: + resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} engines: {node: '>=10'} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} - engines: {node: '>= 4'} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -738,33 +1479,38 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -776,21 +1522,47 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + hasBin: true + + jsdom@21.1.2: + resolution: {integrity: sha512-sCpFmK2jv+1sjff4u7fzft+pUh2KSUbUrEHYHyfSIbGTIcmnjyp83qg6qLwdJ/I3LpTXx33ACxeRL7Lsyc6lGQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-ref-resolver@1.0.1: resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + kuler@2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + light-my-request@5.11.0: resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -803,8 +1575,24 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} log-update@5.0.1: resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} @@ -814,20 +1602,15 @@ packages: resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==} engines: {node: '>= 12.0.0'} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -844,19 +1627,52 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + mitt@3.0.0: + resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-cache@5.1.2: + resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} + engines: {node: '>= 8.0.0'} + + node-fetch@2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + nwsapi@2.2.24: + resolution: {integrity: sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -876,6 +1692,21 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -888,52 +1719,90 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - pino-abstract-transport@1.1.0: - resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} - pino-std-serializers@6.2.2: - resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} - pino@8.16.2: - resolution: {integrity: sha512-2advCDGVEvkKu9TTVSa/kWW7Z3htI/sBKEZpqiHk6ive0i/7f5b1rsU8jn0aimxqfnSz5bj/nOYkwhBUn5xxvg==} + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} hasBin: true pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - playwright-core@1.47.2: - resolution: {integrity: sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + playwright-core@1.54.2: + resolution: {integrity: sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==} engines: {node: '>=18'} hasBin: true - playwright@1.47.2: - resolution: {integrity: sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==} + playwright@1.54.2: + resolution: {integrity: sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==} engines: {node: '>=18'} hasBin: true - postcss-load-config@4.0.1: - resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} - engines: {node: '>= 14'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: + jiti: '>=1.21.0' postcss: '>=8.0.9' - ts-node: '>=9.0.0' + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} + engines: {node: ^10 || ^12 || >=14} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@2.3.0: resolution: {integrity: sha512-N6mp1+2jpQr3oCFMz6SeHRGbv6Slb20bRhj4v3xR99HqNToAcOe1MFOp4tytyzOfJn+QtN8Rf7U/h2KAn4kC6g==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} @@ -942,47 +1811,87 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + puppeteer-core@19.11.1: + resolution: {integrity: sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==} + engines: {node: '>=14.14.0'} + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + + puppeteer@19.11.1: + resolution: {integrity: sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==} + deprecated: < 24.15.0 is no longer supported + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.4.2: - resolution: {integrity: sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - ret@0.2.2: - resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} - engines: {node: '>=4'} + ret@0.4.3: + resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==} + engines: {node: '>=10'} reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -991,32 +1900,37 @@ packages: rfdc@1.3.0: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} - rollup@3.29.4: - resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rrweb-cssom@0.6.0: + resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex2@2.0.0: - resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + safe-regex2@3.1.0: + resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==} safe-stable-stringify@2.4.3: resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} engines: {node: '>=10'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -1037,58 +1951,91 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} - sonic-boom@3.7.0: - resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + split@1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - sucrase@3.34.0: - resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} - engines: {node: '>=8'} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} hasBin: true supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} @@ -1099,19 +2046,54 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - thread-stream@2.4.1: - resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} + thread-stream@3.2.0: + resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinygradient@1.1.5: + resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} toad-cache@3.3.0: resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==} engines: {node: '>=12'} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@4.1.1: + resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} + engines: {node: '>=14'} tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} @@ -1127,15 +2109,18 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - tsup@7.2.0: - resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} - engines: {node: '>=16.14'} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} hasBin: true peerDependencies: + '@microsoft/api-extractor': ^7.36.0 '@swc/core': ^1 postcss: ^8.4.12 - typescript: '>=4.1.0' + typescript: '>=4.5.0' peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true '@swc/core': optional: true postcss: @@ -1143,6 +2128,10 @@ packages: typescript: optional: true + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + type-fest@1.4.0: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} @@ -1152,39 +2141,154 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - winston-transport@4.6.0: - resolution: {integrity: sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==} - engines: {node: '>= 12.0.0'} - - winston@3.10.0: - resolution: {integrity: sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==} + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@12.0.1: + resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} + engines: {node: '>=14'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + + winston-transport@4.6.0: + resolution: {integrity: sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==} engines: {node: '>= 12.0.0'} + winston@3.10.0: + resolution: {integrity: sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==} + engines: {node: '>= 12.0.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} @@ -1192,15 +2296,66 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - yaml@2.3.4: - resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} - engines: {node: '>= 14'} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.1: + resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} + engines: {node: '>=12'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} snapshots: + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.29.7': {} + '@colors/colors@1.5.0': {} '@colors/colors@1.6.0': {} @@ -1216,70 +2371,151 @@ snapshots: tslib: 2.6.3 optional: true - '@esbuild/android-arm64@0.18.20': + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/android-arm@0.18.20': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/android-x64@0.18.20': + '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/darwin-arm64@0.18.20': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/darwin-x64@0.18.20': + '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.18.20': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.18.20': + '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-arm64@0.18.20': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-arm@0.18.20': + '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-ia32@0.18.20': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-loong64@0.18.20': + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/linux-mips64el@0.18.20': + '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/linux-ppc64@0.18.20': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.18.20': + '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/linux-s390x@0.18.20': + '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/linux-x64@0.18.20': + '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.18.20': + '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.18.20': + '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/sunos-x64@0.18.20': + '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/win32-arm64@0.18.20': + '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/win32-ia32@0.18.20': + '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-x64@0.18.20': + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.27.7': optional: true '@fastify/ajv-compiler@3.5.0': @@ -1383,57 +2619,230 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.20': dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - '@nodelib/fs.scandir@2.1.5': + '@lambdatest/node-tunnel@4.0.11': dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + adm-zip: 0.5.18 + axios: 1.18.1 + get-port: 1.0.0 + https-proxy-agent: 5.0.1 + split: 1.0.1 + transitivePeerDependencies: + - debug + - supports-color - '@nodelib/fs.stat@2.0.5': {} + '@pinojs/redact@0.4.0': {} - '@nodelib/fs.walk@1.2.8': + '@playwright/browser-chromium@1.54.2': dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + playwright-core: 1.54.2 - '@playwright/browser-chromium@1.47.2': + '@playwright/browser-firefox@1.54.2': dependencies: - playwright-core: 1.47.2 + playwright-core: 1.54.2 - '@playwright/browser-firefox@1.47.2': + '@playwright/browser-webkit@1.54.2': dependencies: - playwright-core: 1.47.2 + playwright-core: 1.54.2 - '@playwright/browser-webkit@1.47.2': + '@playwright/test@1.54.2': dependencies: - playwright-core: 1.47.2 + playwright: 1.54.2 - '@playwright/test@1.47.2': + '@puppeteer/browsers@0.5.0(typescript@5.3.2)': dependencies: - playwright: 1.47.2 + debug: 4.3.4 + extract-zip: 2.0.1 + https-proxy-agent: 5.0.1 + progress: 2.0.3 + proxy-from-env: 1.1.0 + tar-fs: 2.1.1 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + optionalDependencies: + typescript: 5.3.2 + transitivePeerDependencies: + - supports-color + + '@rollup/rollup-android-arm-eabi@4.62.2': + optional: true + + '@rollup/rollup-android-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-x64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.2': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.2': + optional: true + + '@tootallnate/once@2.0.1': {} + + '@types/archiver@5.3.4': + dependencies: + '@types/readdir-glob': 1.1.5 '@types/cross-spawn@6.0.5': dependencies: '@types/node': 20.9.0 + '@types/estree@1.0.9': {} + + '@types/json-stringify-safe@5.0.3': {} + '@types/node@20.9.0': dependencies: undici-types: 5.26.5 + '@types/readdir-glob@1.1.5': + dependencies: + '@types/node': 20.9.0 + + '@types/tinycolor2@1.4.6': {} + '@types/triple-beam@1.3.5': {} '@types/which@3.0.2': {} - abort-controller@3.0.0: + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 20.9.0 + optional: true + + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.9.0))': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21(@types/node@20.9.0) + + '@vitest/pretty-format@2.1.9': dependencies: - event-target-shim: 5.0.1 + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.9': + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + + abab@2.0.6: {} abstract-logging@2.0.1: {} + acorn-globals@7.0.1: + dependencies: + acorn: 8.17.0 + acorn-walk: 8.3.5 + + acorn-walk@8.3.5: + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + adm-zip@0.5.18: {} + + agent-base@6.0.2: + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.4: {} + ajv-errors@3.0.0(ajv@8.12.0): dependencies: ajv: 8.12.0 @@ -1449,10 +2858,16 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + ansi-escapes@5.0.0: dependencies: type-fest: 1.4.0 + ansi-regex@5.0.1: {} + ansi-regex@6.0.1: {} ansi-styles@4.3.0: @@ -1463,14 +2878,45 @@ snapshots: any-promise@1.3.0: {} - anymatch@3.1.3: + archiver-utils@2.1.0: + dependencies: + glob: 7.1.6 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + + archiver-utils@3.0.4: dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 normalize-path: 3.0.0 - picomatch: 2.3.1 + readable-stream: 3.6.2 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.5 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.1 - archy@1.0.0: {} + argparse@2.0.1: {} - array-union@2.1.0: {} + assertion-error@2.0.1: {} async@3.2.5: {} @@ -1478,75 +2924,133 @@ snapshots: atomic-sleep@1.0.0: {} - avvio@8.2.1: + avvio@8.4.0: dependencies: - archy: 1.0.0 - debug: 4.3.4 - fastq: 1.15.0 - transitivePeerDependencies: - - supports-color + '@fastify/error': 3.4.1 + fastq: 1.20.1 - axios@1.6.2: + axios@1.18.1: dependencies: - follow-redirects: 1.15.3 - form-data: 4.0.0 - proxy-from-env: 1.1.0 + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color balanced-match@1.0.2: {} base64-js@1.5.1: {} - binary-extensions@2.2.0: {} + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + boxen@5.1.2: + dependencies: + ansi-align: 3.0.1 + camelcase: 6.3.0 + chalk: 4.1.2 + cli-boxes: 2.2.1 + string-width: 4.2.3 + type-fest: 0.20.2 + widest-line: 3.1.0 + wrap-ansi: 7.0.0 brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - braces@3.0.2: + brace-expansion@2.1.2: dependencies: - fill-range: 7.0.1 + balanced-match: 1.0.2 + + buffer-crc32@0.2.13: {} - buffer@6.0.3: + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - bundle-require@4.0.2(esbuild@0.18.20): + bundle-require@5.1.0(esbuild@0.27.7): dependencies: - esbuild: 0.18.20 + esbuild: 0.27.7 load-tsconfig: 0.2.5 cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chokidar@3.5.3: + check-error@2.1.3: {} + + chokidar@4.0.3: dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 + readdirp: 4.1.2 + + chownr@1.1.4: {} + + chromium-bidi@0.4.7(devtools-protocol@0.0.1107588): + dependencies: + devtools-protocol: 0.0.1107588 + mitt: 3.0.0 + + cli-boxes@2.2.1: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 cli-cursor@4.0.0: dependencies: restore-cursor: 4.0.0 + cli-spinners@2.9.2: {} + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@3.1.0: dependencies: slice-ansi: 5.0.0 string-width: 5.1.2 + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + clone@2.1.2: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -1587,78 +3091,218 @@ snapshots: commander@11.1.0: {} + commander@14.0.3: {} + commander@4.1.1: {} + compress-commons@4.1.2: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.3 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + concat-map@0.0.1: {} + confbox@0.1.8: {} + + consola@3.4.2: {} + cookie@0.5.0: {} - cross-spawn@7.0.3: + core-util-is@1.0.3: {} + + cosmiconfig@8.1.3: + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + + crc-32@1.2.2: {} + + crc32-stream@4.0.3: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + cross-fetch@3.1.5: + dependencies: + node-fetch: 2.6.7 + transitivePeerDependencies: + - encoding + + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + cssstyle@3.0.0: + dependencies: + rrweb-cssom: 0.6.0 + + data-urls@4.0.0: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 12.0.1 + debug@4.3.4: dependencies: ms: 2.1.2 + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + deep-eql@5.0.2: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + delayed-stream@1.0.0: {} detect-libc@2.0.3: {} - dir-glob@3.0.1: + devtools-protocol@0.0.1107588: {} + + domexception@4.0.0: dependencies: - path-type: 4.0.0 + webidl-conversions: 7.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 eastasianwidth@0.2.0: {} + emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} enabled@2.0.0: {} - esbuild@0.18.20: + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + entities@6.0.1: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.27.7: optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - event-target-shim@5.0.1: {} + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escalade@3.2.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 - eventemitter3@5.0.1: {} + esprima@4.0.1: {} - events@3.3.0: {} + estraverse@5.3.0: {} - execa@5.1.1: + estree-walker@3.0.3: dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + expect-type@1.4.0: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.3.4 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color fast-content-type-parse@1.1.0: {} @@ -1666,14 +3310,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - fast-json-stringify@5.9.1: dependencies: '@fastify/deepmerge': 1.3.0 @@ -1688,59 +3324,75 @@ snapshots: dependencies: fast-decode-uri-component: 1.0.1 - fast-redact@3.3.0: {} - fast-uri@2.3.0: {} - fastify@4.24.3: + fastify@4.29.1: dependencies: '@fastify/ajv-compiler': 3.5.0 '@fastify/error': 3.4.1 '@fastify/fast-json-stringify-compiler': 4.3.0 abstract-logging: 2.0.1 - avvio: 8.2.1 + avvio: 8.4.0 fast-content-type-parse: 1.1.0 fast-json-stringify: 5.9.1 - find-my-way: 7.7.0 + find-my-way: 8.2.2 light-my-request: 5.11.0 - pino: 8.16.2 - process-warning: 2.3.0 + pino: 9.14.0 + process-warning: 3.0.0 proxy-addr: 2.0.7 rfdc: 1.3.0 secure-json-parse: 2.7.0 - semver: 7.5.4 + semver: 7.6.3 toad-cache: 3.3.0 - transitivePeerDependencies: - - supports-color - fastq@1.15.0: + fastq@1.20.1: dependencies: reusify: 1.0.4 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + fecha@4.2.3: {} - fill-range@7.0.1: + figlet@1.11.0: dependencies: - to-regex-range: 5.0.1 + commander: 14.0.3 + + find-free-port@2.0.0: {} - find-my-way@7.7.0: + find-my-way@8.2.2: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 - safe-regex2: 2.0.0 + safe-regex2: 3.1.0 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.62.2 fn.name@1.1.0: {} - follow-redirects@1.15.3: {} + follow-redirects@1.16.0: {} - form-data@4.0.0: + form-data@4.0.6: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 mime-types: 2.1.35 forwarded@0.2.0: {} + fs-constants@1.0.0: {} + fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -1749,11 +3401,33 @@ snapshots: fsevents@2.3.3: optional: true - get-stream@6.0.1: {} + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-port@1.0.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 - glob-parent@5.1.2: + get-stream@5.2.0: dependencies: - is-glob: 4.0.3 + pump: 3.0.4 glob@7.1.6: dependencies: @@ -1764,22 +3438,79 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - globby@11.1.0: + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + gradient-string@2.0.2: dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.0 - merge2: 1.4.1 - slash: 3.0.0 + chalk: 4.1.2 + tinygradient: 1.1.5 has-flag@4.0.0: {} - human-signals@2.1.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + html-encoding-sniffer@3.0.0: + dependencies: + whatwg-encoding: 2.0.0 + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.1 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 ieee754@1.2.1: {} - ignore@5.3.0: {} + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 inflight@1.0.6: dependencies: @@ -1790,45 +3521,92 @@ snapshots: ipaddr.js@1.9.1: {} - is-arrayish@0.3.2: {} + is-arrayish@0.2.1: {} - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.2.0 + is-arrayish@0.3.2: {} - is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 + is-interactive@1.0.0: {} - is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: {} is-stream@2.0.1: {} + is-unicode-supported@0.1.0: {} + + isarray@1.0.0: {} + isexe@2.0.0: {} isexe@3.1.1: {} joycon@3.1.1: {} + js-tokens@4.0.0: {} + + js-yaml@4.3.0: + dependencies: + argparse: 2.0.1 + + jsdom@21.1.2: + dependencies: + abab: 2.0.6 + acorn: 8.17.0 + acorn-globals: 7.0.1 + cssstyle: 3.0.0 + data-urls: 4.0.0 + decimal.js: 10.6.0 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.6 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.24 + parse5: 7.3.0 + rrweb-cssom: 0.6.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 12.0.1 + ws: 8.21.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + json-parse-even-better-errors@2.3.1: {} + json-schema-ref-resolver@1.0.1: dependencies: fast-deep-equal: 3.1.3 json-schema-traverse@1.0.0: {} + json-stringify-safe@5.0.1: {} + kuler@2.0.0: {} + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + light-my-request@5.11.0: dependencies: cookie: 0.5.0 process-warning: 2.3.0 set-cookie-parser: 2.6.0 - lilconfig@2.1.0: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -1843,7 +3621,20 @@ snapshots: load-tsconfig@0.2.5: {} - lodash.sortby@4.7.0: {} + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.flatten@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.union@4.6.0: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 log-update@5.0.1: dependencies: @@ -1862,18 +3653,13 @@ snapshots: safe-stable-stringify: 2.4.3 triple-beam: 1.4.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} + loupe@3.2.1: {} - micromatch@4.0.5: + magic-string@0.30.21: dependencies: - braces: 3.0.2 - picomatch: 2.3.1 + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} mime-db@1.52.0: {} @@ -1887,19 +3673,44 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.2 + + mitt@3.0.0: {} + + mkdirp-classic@0.5.3: {} + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + ms@2.1.2: {} + ms@2.1.3: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - normalize-path@3.0.0: {} + nanoid@3.3.15: {} - npm-run-path@4.0.1: + node-cache@5.1.2: dependencies: - path-key: 3.1.1 + clone: 2.1.2 + + node-fetch@2.6.7: + dependencies: + whatwg-url: 5.0.0 + + normalize-path@3.0.0: {} + + nwsapi@2.2.24: {} object-assign@4.1.1: {} @@ -1917,53 +3728,108 @@ snapshots: dependencies: mimic-fn: 2.1.0 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + path-is-absolute@1.0.1: {} path-key@3.1.1: {} path-type@4.0.0: {} - picomatch@2.3.1: {} + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pend@1.2.0: {} - pino-abstract-transport@1.1.0: + picocolors@1.1.1: {} + + picomatch@4.0.5: {} + + pino-abstract-transport@2.0.0: dependencies: - readable-stream: 4.4.2 split2: 4.2.0 - pino-std-serializers@6.2.2: {} + pino-std-serializers@7.1.0: {} - pino@8.16.2: + pino@9.14.0: dependencies: + '@pinojs/redact': 0.4.0 atomic-sleep: 1.0.0 - fast-redact: 3.3.0 on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.1.0 - pino-std-serializers: 6.2.2 - process-warning: 2.3.0 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.4.3 - sonic-boom: 3.7.0 - thread-stream: 2.4.1 + sonic-boom: 4.2.1 + thread-stream: 3.2.0 pirates@4.0.6: {} - playwright-core@1.47.2: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + playwright-core@1.54.2: {} - playwright@1.47.2: + playwright@1.54.2: dependencies: - playwright-core: 1.47.2 + playwright-core: 1.54.2 optionalDependencies: fsevents: 2.3.2 - postcss-load-config@4.0.1: + postcss-load-config@6.0.1(postcss@8.5.16): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.16 + + postcss@8.5.16: dependencies: - lilconfig: 2.1.0 - yaml: 2.3.4 + nanoid: 3.3.15 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + process-nextick-args@2.0.1: {} process-warning@2.3.0: {} - process@0.11.10: {} + process-warning@3.0.0: {} + + process-warning@5.0.0: {} + + progress@2.0.3: {} proxy-addr@2.0.7: dependencies: @@ -1972,68 +3838,159 @@ snapshots: proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} - queue-microtask@1.2.3: {} + puppeteer-core@19.11.1(typescript@5.3.2): + dependencies: + '@puppeteer/browsers': 0.5.0(typescript@5.3.2) + chromium-bidi: 0.4.7(devtools-protocol@0.0.1107588) + cross-fetch: 3.1.5 + debug: 4.3.4 + devtools-protocol: 0.0.1107588 + extract-zip: 2.0.1 + https-proxy-agent: 5.0.1 + proxy-from-env: 1.1.0 + tar-fs: 2.1.1 + unbzip2-stream: 1.4.3 + ws: 8.13.0 + optionalDependencies: + typescript: 5.3.2 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + puppeteer@19.11.1(typescript@5.3.2): + dependencies: + '@puppeteer/browsers': 0.5.0(typescript@5.3.2) + cosmiconfig: 8.1.3 + https-proxy-agent: 5.0.1 + progress: 2.0.3 + proxy-from-env: 1.1.0 + puppeteer-core: 19.11.1(typescript@5.3.2) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - typescript + - utf-8-validate + + querystringify@2.2.0: {} quick-format-unescaped@4.0.4: {} - readable-stream@3.6.2: + readable-stream@2.3.8: dependencies: + core-util-is: 1.0.3 inherits: 2.0.4 - string_decoder: 1.3.0 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 util-deprecate: 1.0.2 - readable-stream@4.4.2: + readable-stream@3.6.2: dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 + inherits: 2.0.4 string_decoder: 1.3.0 + util-deprecate: 1.0.2 - readdirp@3.6.0: + readdir-glob@1.1.3: dependencies: - picomatch: 2.3.1 + minimatch: 5.1.9 + + readdirp@4.1.2: {} real-require@0.2.0: {} + require-directory@2.1.1: {} + require-from-string@2.0.2: {} + requires-port@1.0.0: {} + + resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + restore-cursor@4.0.0: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 - ret@0.2.2: {} + ret@0.4.3: {} reusify@1.0.4: {} rfdc@1.3.0: {} - rollup@3.29.4: + rollup@4.62.2: + dependencies: + '@types/estree': 1.0.9 optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 fsevents: 2.3.3 - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 + rrweb-cssom@0.6.0: {} + + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} - safe-regex2@2.0.0: + safe-regex2@3.1.0: dependencies: - ret: 0.2.2 + ret: 0.4.3 safe-stable-stringify@2.4.3: {} - secure-json-parse@2.7.0: {} + safer-buffer@2.1.2: {} - semver@7.5.4: + saxes@6.0.0: dependencies: - lru-cache: 6.0.0 + xmlchars: 2.2.0 + + secure-json-parse@2.7.0: {} semver@7.6.3: {} @@ -2071,61 +4028,101 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + signal-exit@3.0.7: {} simple-swizzle@0.2.2: dependencies: is-arrayish: 0.3.2 - slash@3.0.0: {} - slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.1 is-fullwidth-code-point: 4.0.0 - sonic-boom@3.7.0: + sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 + source-map-js@1.2.1: {} + + source-map@0.6.1: + optional: true + + source-map@0.7.6: {} split2@4.2.0: {} + split@1.0.1: + dependencies: + through: 2.3.8 + stack-trace@0.0.10: {} + stackback@0.0.2: {} + + std-env@3.10.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string-width@5.1.2: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-ansi@7.1.0: dependencies: ansi-regex: 6.0.1 - strip-final-newline@2.0.0: {} - - sucrase@3.34.0: + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.3 commander: 4.1.1 - glob: 7.1.6 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 + tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 supports-color@7.2.0: dependencies: has-flag: 4.0.0 + symbol-tree@3.2.4: {} + + tar-fs@2.1.1: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + text-hex@1.0.0: {} thenify-all@1.6.0: @@ -2136,17 +4133,46 @@ snapshots: dependencies: any-promise: 1.3.0 - thread-stream@2.4.1: + thread-stream@3.2.0: dependencies: real-require: 0.2.0 - to-regex-range@5.0.1: + through@2.3.8: {} + + tinybench@2.9.0: {} + + tinycolor2@1.6.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + tinygradient@1.1.5: dependencies: - is-number: 7.0.0 + '@types/tinycolor2': 1.4.6 + tinycolor2: 1.6.0 + + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} toad-cache@3.3.0: {} - tr46@1.0.1: + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@0.0.3: {} + + tr46@4.1.1: dependencies: punycode: 2.3.1 @@ -2159,47 +4185,154 @@ snapshots: tslib@2.6.3: optional: true - tsup@7.2.0(typescript@5.3.2): + tsup@8.5.1(postcss@8.5.16)(typescript@5.3.2): dependencies: - bundle-require: 4.0.2(esbuild@0.18.20) + bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 - esbuild: 0.18.20 - execa: 5.1.1 - globby: 11.1.0 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 - postcss-load-config: 4.0.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.16) resolve-from: 5.0.0 - rollup: 3.29.4 - source-map: 0.8.0-beta.0 - sucrase: 3.34.0 + rollup: 4.62.2 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 tree-kill: 1.2.2 optionalDependencies: + postcss: 8.5.16 typescript: 5.3.2 transitivePeerDependencies: + - jiti - supports-color - - ts-node + - tsx + - yaml + + type-fest@0.20.2: {} type-fest@1.4.0: {} typescript@5.3.2: {} + ufo@1.6.4: {} + + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + undici-types@5.26.5: {} + universalify@0.2.0: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + util-deprecate@1.0.2: {} - webidl-conversions@4.0.2: {} + uuid@11.1.1: {} + + vite-node@2.1.9(@types/node@20.9.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@20.9.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@20.9.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.16 + rollup: 4.62.2 + optionalDependencies: + '@types/node': 20.9.0 + fsevents: 2.3.3 + + vitest@2.1.9(@types/node@20.9.0)(jsdom@21.1.2): + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.9.0)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@20.9.0) + vite-node: 2.1.9(@types/node@20.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.9.0 + jsdom: 21.1.2 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + w3c-xmlserializer@4.0.0: + dependencies: + xml-name-validator: 4.0.0 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + whatwg-encoding@2.0.0: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@3.0.0: {} + + whatwg-url@12.0.1: + dependencies: + tr46: 4.1.1 + webidl-conversions: 7.0.0 - whatwg-url@7.1.0: + whatwg-url@5.0.0: dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 + tr46: 0.0.3 + webidl-conversions: 3.0.1 which@2.0.2: dependencies: @@ -2209,6 +4342,15 @@ snapshots: dependencies: isexe: 3.1.1 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + widest-line@3.1.0: + dependencies: + string-width: 4.2.3 + winston-transport@4.6.0: dependencies: logform: 2.6.0 @@ -2229,6 +4371,12 @@ snapshots: triple-beam: 1.4.1 winston-transport: 4.6.0 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@8.1.0: dependencies: ansi-styles: 6.2.1 @@ -2237,6 +4385,35 @@ snapshots: wrappy@1.0.2: {} - yallist@4.0.0: {} + ws@8.13.0: {} + + ws@8.21.0: {} + + xml-name-validator@4.0.0: {} - yaml@2.3.4: {} + xmlchars@2.2.0: {} + + y18n@5.0.8: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.1: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + zip-stream@4.1.1: + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 diff --git a/src/commander/commander.ts b/src/commander/commander.ts index 0e6bac9..12538fa 100644 --- a/src/commander/commander.ts +++ b/src/commander/commander.ts @@ -1,8 +1,9 @@ import { Command } from 'commander' import exec from './exec.js' -import { configWeb, configStatic, configFigma, configWebFigma, configAppFigma} from './config.js' +import { configWeb, configStatic, configFigma, configWebFigma, configAppFigma, configStorybook} from './config.js' import capture from './capture.js' import upload from './upload.js' +import storybook from './storybook.js' import { version } from '../../package.json' import { uploadFigma, uploadWebFigmaCommand,uploadAppFigmaCommand } from './uploadFigma.js' import startServer from './server.js'; @@ -32,6 +33,8 @@ program .addCommand(capture) .addCommand(configWeb) .addCommand(configStatic) + .addCommand(configStorybook) + .addCommand(storybook) .addCommand(upload) .addCommand(startServer) .addCommand(stopServer) diff --git a/src/commander/config.ts b/src/commander/config.ts index 546d73e..283570d 100644 --- a/src/commander/config.ts +++ b/src/commander/config.ts @@ -1,11 +1,12 @@ import { Command } from 'commander' -import { createConfig, createWebStaticConfig, createFigmaConfig, createWebFigmaConfig, createAppFigmaConfig } from '../lib/config.js' +import { createConfig, createWebStaticConfig, createFigmaConfig, createWebFigmaConfig, createAppFigmaConfig, createStorybookConfig } from '../lib/config.js' export const configWeb = new Command(); export const configStatic = new Command(); export const configFigma = new Command(); export const configWebFigma = new Command(); export const configAppFigma = new Command(); +export const configStorybook = new Command(); configWeb @@ -24,6 +25,14 @@ configStatic createWebStaticConfig(filepath); }) +configStorybook + .name('config:create-storybook') + .description('Create SmartUI Storybook config file') + .argument('[filepath]', 'Optional config filepath') + .action(async function(filepath, options) { + createStorybookConfig(filepath); + }) + configFigma .name('config:create-figma') .description('Create figma designs config file') diff --git a/src/commander/storybook.ts b/src/commander/storybook.ts new file mode 100644 index 0000000..eb5c508 --- /dev/null +++ b/src/commander/storybook.ts @@ -0,0 +1,216 @@ +import { Command, Option } from 'commander' +import fs from 'fs' +// Faithful vendored relocation of the proven @lambdatest/smartui-storybook engine. +// The Storybook capture path talks to the same /storybook/* backend the standalone +// package already uses in production, so behavior is unchanged. It now simply lives +// inside the single unified `smartui` binary (no more colliding bins / double install). +import vendor, { type StorybookRunOptions } from '../storybookVendor/index.cjs' +import tui from '../lib/tui.cjs' +const { runStorybook, redactSecrets } = vendor + +type Mode = 'url' | 'dir'; + +interface RunPreview { + browsers: string; + viewports: string; + stories?: string; +} + +/** Shape of a `storybook` block as far as the preview cares. Everything is optional + * because this runs before the engine validates the config. */ +interface StorybookConfigBlock { + browsers?: unknown; + resolutions?: unknown; + viewports?: unknown; +} + +/** A Storybook story index entry, in either the legacy or the >= 8 payload shape. */ +interface StoryIndexEntry { + type?: string; +} + +// Best-effort preview of what this run will cover (never throws). +function preview(target: string, mode: Mode, configPath?: string): RunPreview { + let browsers = 'chrome, firefox, safari, edge'; + let viewports = '1920×1080'; + let stories: string | undefined; + try { + if (configPath && fs.existsSync(configPath)) { + const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8')) as { storybook?: StorybookConfigBlock }; + const sb: StorybookConfigBlock = parsed.storybook ?? {}; + if (Array.isArray(sb.browsers) && sb.browsers.length) browsers = sb.browsers.join(', '); + const vp = sb.resolutions ?? sb.viewports; + if (Array.isArray(vp) && vp.length) { + viewports = vp.map((v: unknown) => (Array.isArray(v) ? v.join('×') : String(v))).join(' '); + } + } + } catch (_) { /* preview only: a malformed config is the engine's error to report */ } + try { + if (mode === 'dir') { + const idx = fs.existsSync(`${target}/stories.json`) ? `${target}/stories.json` + : fs.existsSync(`${target}/index.json`) ? `${target}/index.json` : null; + if (idx) { + const j = JSON.parse(fs.readFileSync(idx, 'utf8')) as { + stories?: Record; + entries?: Record; + }; + const entries = j.stories ?? j.entries ?? {}; + const n = Object.values(entries).filter((e) => e.type !== 'docs').length; + stories = `${n} stories`; + } + } + } catch (_) { /* preview only: the engine reports a bad or missing index itself */ } + return { browsers, viewports, stories }; +} + +/** Options commander hands the action, before global flags are merged in. */ +interface StorybookCommandOptions extends StorybookRunOptions { + config?: string; + forceRebuild?: boolean; + buildName?: string; + env?: 'prod' | 'stage'; +} + +const command = new Command(); + +command + .name('storybook') + .description('Snapshot Storybook stories (URL or static build directory)') + .argument('', 'Storybook server URL or path to a storybook-static build directory') + .option('-c, --config ', 'Config file path') + .option('--force-rebuild', 'Force a rebuild of an already existing build', false) + .option('--buildName ', 'Specify the build name for the pipeline') + .addOption(new Option('--env ', 'Runtime environment').choices(['prod', 'stage'])) + .action(async function (target: string, options: StorybookCommandOptions, command: Command) { + // Merge root-level global flags (e.g. --config, --markBaseline) so they reach + // the engine even when the same flag exists globally and locally. + const globals = command.optsWithGlobals(); + options.config = options.config || globals['config']; + options.env = options.env || 'prod'; + const mode: Mode = /^https?:\/\//.test(target) ? 'url' : 'dir'; + const p = preview(target, mode, options.config); + + tui.banner(); + tui.runHeader({ + target, + mode, + buildName: options.buildName, + env: options.env, + configPath: options.config, + browsers: p.browsers, + viewports: p.viewports, + storyHint: p.stories, + }); + + // Tee stdout so we can parse the final build stats for a summary box. + // The engine's polling isn't fully awaited, so we print the summary on + // 'beforeExit'. That fires only once the event loop drains, i.e. after + // polling truly finishes, guaranteeing the box is the last thing shown. + // + // Only a bounded tail is kept. The engine prints the serialised DOM and CSS of every + // story, which is roughly 360 KB of stdout for 17 stories, so buffering all of it to + // pull out five numbers would hold tens of megabytes on a large Storybook. Every stat + // below appears in the build-details block at the very end, well inside the tail. + // Failure lines can appear at any point, so those are latched as they stream past + // rather than searched for afterwards. + const TAIL_LIMIT = 64 * 1024; + const origLog = console.log; + let captured = ''; + let sawFailure = false; + let sawBaseline = false; + console.log = (...a: unknown[]) => { + // Scrub on the way out. The engine prints server-supplied messages, and at least one + // backend error echoes the caller's access key, which would otherwise land in stdout + // and in CI logs. + a = a.map((x) => (typeof x === 'string' ? redactSecrets(x) : x)); + const line = a.map(String).join(' ') + '\n'; + if (/Build failed|\[smartui\] Error:/i.test(line)) sawFailure = true; + if (/baseline build/i.test(line)) sawBaseline = true; + captured += line; + if (captured.length > TAIL_LIMIT) captured = captured.slice(-TAIL_LIMIT); + origLog(...a); + }; + + const grab = (re: RegExp): string | undefined => captured.match(re)?.[1]; + + // Pull a usable failure line out of the tail. The engine is inconsistent about this: + // some paths log "Build failed: Error: ", others log a descriptive line with + // an empty message after "Error:" (an unreachable Storybook prints + // "Connection to storybook not established. Error: " and nothing more). Taking only the + // text after "Error:" therefore produced an empty box. Walk back through the engine's + // own lines instead and use the last one that says something. + const failureMessage = (): string | undefined => { + const lines = captured.split('\n').reverse(); + for (const raw of lines) { + const line = raw.replace(/^\[smartui\]\s*/, '').trim(); + if (!line) continue; + if (!/error|failed|not established|cannot|invalid|no stories/i.test(line)) continue; + // Drop a dangling "Error:" with nothing after it, then keep whatever is left. + const cleaned = line.replace(/\s*Error:\s*$/i, '').replace(/\s+/g, ' ').trim(); + if (cleaned) return cleaned; + } + return undefined; + }; + // Exit code 3 is the engine's "a build already exists for this commit" signal. It is a + // deliberate skip, not a failure, and it must not be painted red. + const BUILD_ALREADY_EXISTS = 3; + + let printed = false; + const printSummary = () => { + if (printed) return; printed = true; + console.log = origLog; + const code = typeof process.exitCode === 'number' ? process.exitCode : 0; + if (code === BUILD_ALREADY_EXISTS) { + tui.box(tui.paint('Storybook build skipped'), [ + 'A build already exists for this commit on this branch.', + tui.dim('Pass --force-rebuild to push a new one.'), + ], { tag: ' skipped ', color: 'yellow' }); + return; + } + const failed = sawFailure || code !== 0; + if (failed) { tui.resultBox(false, { message: failureMessage() }); return; } + const url = grab(/Build URL:\s*(\S+)/i); + const screenshots = grab(/Total Screenshots:\s*(\d+)/i); + const stats = tui.kv([ + ['Screenshots', screenshots], + ['Approved', grab(/Approved:\s*(\d+)/i)], + ['Changes found', grab(/Changes found:\s*(\d+)/i)], + ['Rejected', grab(/Rejected:\s*(\d+)/i)], + ['Baseline', sawBaseline ? 'yes (first run, no comparisons)' : undefined], + ]); + // kv() drops empty values, so guard the lookup rather than assuming a row exists. + const dashboardRow = url ? tui.kv([['Dashboard', url]])[0] : undefined; + if (dashboardRow) stats.unshift(dashboardRow); + + // A build that captured nothing still reports success and exits 0, so in CI it is + // indistinguishable from a passing visual test run. The exit code is a contract we + // are not changing here, but the run should at least say so out loud. + const capturedNothing = screenshots === '0'; + if (capturedNothing) { + stats.push(tui.dim('No screenshots were captured. Nothing was compared.')); + } + tui.box( + `${tui.paint(capturedNothing ? 'Storybook build complete, but empty' : 'Storybook build complete')}`, + stats.length ? stats : [tui.dim('See log above.')], + { tag: capturedNothing ? ' warning ' : ' done ', color: capturedNothing ? 'yellow' : 'green' }, + ); + }; + // beforeExit covers the normal path, where the engine's polling is still draining the + // event loop. It does NOT fire when the engine calls process.exit() directly, which it + // does for "No stories found", an unreachable Storybook and similar. Hooking 'exit' as + // well means every run ends with a summary instead of trailing off after the launch box. + // Writes from an 'exit' handler are synchronous and survive both pipes and files. + process.once('beforeExit', printSummary); + process.once('exit', printSummary); + + try { + await runStorybook(target, options); + } catch (error: unknown) { + console.log = origLog; + printed = true; + tui.resultBox(false, { message: error instanceof Error ? error.message : String(error) }); + process.exitCode = 1; + } + }) + +export default command; diff --git a/src/lib/config.ts b/src/lib/config.ts index a98e2eb..25601df 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -3,6 +3,35 @@ import fs from 'fs' import constants from './constants.js'; import { Context } from "../types.js"; +// Read a config file that is about to be merged into. +// +// Returns the parsed object, or an error message explaining why it cannot be merged. Both +// generators write to the same default .smartui.json, so they have to cope with whatever is +// already there. Three shapes used to go wrong: a leading BOM (editors add one, JSON.parse +// rejects it), a JSON array (assigning a block to it succeeded, then JSON.stringify dropped the +// property and the file was rewritten unchanged while the CLI reported success), and a bare +// `null` (crashed with an unhandled TypeError and a Node stack trace). +function readMergeableConfig(filepath: string): { config?: Record, error?: string } { + let raw: string; + try { + raw = fs.readFileSync(filepath, 'utf-8'); + } catch (error: any) { + return { error: `Cannot read existing config ${filepath}: ${error.message}` }; + } + + let parsed: unknown; + try { + parsed = JSON.parse(raw.replace(/^\uFEFF/, '')); + } catch (error: any) { + return { error: `Cannot read existing config ${filepath}: ${error.message}` }; + } + + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + return { error: `Cannot update ${filepath}: expected a JSON object, found ${Array.isArray(parsed) ? 'an array' : parsed === null ? 'null' : typeof parsed}` }; + } + return { config: parsed as Record }; +} + export function createConfig(filepath: string) { // default filepath filepath = filepath || '.smartui.json'; @@ -12,8 +41,31 @@ export function createConfig(filepath: string) { return } - // verify the file does not already exist if (fs.existsSync(filepath)) { + // The other half of TE-23033. `config:create-storybook` writes to this same default + // path, and the schema lets one file carry both a `web` and a `storybook` block, so + // running the two generators in either order has to work. When the file exists but + // holds only a storybook block, add the web half rather than refusing. + const { config: existingConfig, error } = readMergeableConfig(filepath); + if (error) { + console.log(`Error: ${error}`); + return + } + + if (existingConfig && existingConfig.storybook && !existingConfig.web) { + // Copy every default key the file does not already have, not just `web`, so the + // result matches what running the generators the other way round produces. The + // top-level defaults (waitForTimeout, smartIgnore and friends) are part of a web + // config, and leaving them out would give two different files for the same pair + // of commands. + for (const [key, value] of Object.entries(constants.DEFAULT_CONFIG)) { + if (!(key in existingConfig)) existingConfig[key] = value; + } + fs.writeFileSync(filepath, JSON.stringify(existingConfig, null, 2) + '\n'); + console.log(`Added SmartUI Config to existing config: ${filepath}`); + return + } + console.log(`Error: SmartUI Config already exists: ${filepath}`); console.log(`To create a new file, please specify the file name like: 'smartui config:create .smartui-config.json'`); return @@ -47,6 +99,43 @@ export function createWebStaticConfig(filepath: string) { console.log(`Created web-static config: ${filepath}`); }; +export function createStorybookConfig(filepath: string) { + // default filepath + filepath = filepath || '.smartui.json'; + let filetype = path.extname(filepath); + if (filetype != '.json') { + console.log('Error: Config file must have .json extension'); + return + } + + // `config:create` writes to the same default path, and the config schema lets one file + // carry both a `web` and a `storybook` block. So when the file is already there without + // a storybook block, add the block rather than refusing to write. + if (fs.existsSync(filepath)) { + const { config: existingConfig, error } = readMergeableConfig(filepath); + if (error || !existingConfig) { + console.log(`Error: ${error}`); + return + } + + if (existingConfig.storybook) { + console.log(`Error: SmartUI Storybook config already exists: ${filepath}`); + console.log(`To create a new file, please specify the file name like: 'smartui config:create-storybook .smartui-storybook.json'`); + return + } + + existingConfig.storybook = constants.DEFAULT_STORYBOOK_CONFIG.storybook; + fs.writeFileSync(filepath, JSON.stringify(existingConfig, null, 2) + '\n'); + console.log(`Added SmartUI Storybook config to existing config: ${filepath}`); + return + } + + // write stringified default config options to the filepath + fs.mkdirSync(path.dirname(filepath), { recursive: true }); + fs.writeFileSync(filepath, JSON.stringify(constants.DEFAULT_STORYBOOK_CONFIG, null, 2) + '\n'); + console.log(`Created SmartUI Storybook Config: ${filepath}`); +}; + export function createFigmaConfig(filepath: string) { // default filepath filepath = filepath || 'designs.json'; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 7ec0f44..1036325 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -157,7 +157,36 @@ export default { COMMAND_TYPE_UPLOAD_FIGMA: 'upload-figma', COMMAND_TYPE_UPLOAD_PDF: 'upload-pdf', COMMAND_TYPE_MERGE: 'merge', - ALLOWED_CUSTOM_VIEWPORT_COMMANDS: ['exec', 'exec-start'], + COMMAND_TYPE_STORYBOOK: 'storybook', + // custom viewports apply to exec/exec-start and to storybook dir-mode + ALLOWED_CUSTOM_VIEWPORT_COMMANDS: ['exec', 'exec-start', 'storybook'], + + // storybook backend routes (resolved against SMARTUI_UPLOAD_URL root host) + // TODO(unification, open-Q3): verify endpoint base + payload against backend + STORYBOOK_RENDER_PATH: '/storybook/render', + STORYBOOK_STATIC_RENDER_PATH: '/storybook/staticrender', + STORYBOOK_STATUS_PATH: '/storybook/status', + STORYBOOK_SIGNED_URL_PATH: '/storybook/url', + + // storybook config + VALID_STORYBOOK_BROWSERS: ['chrome', 'firefox', 'safari', 'edge'], + DEFAULT_STORYBOOK_CONFIG: { + storybook: { + browsers: [ + 'chrome', + 'firefox', + 'safari', + 'edge' + ], + viewports: [ + [1920, 1080] + ], + waitForTimeout: 0, + include: [], + exclude: [], + customViewports: [] + } + }, // Default scrollTime DEFAULT_SCROLL_TIME: 8, diff --git a/src/lib/schemaValidation.ts b/src/lib/schemaValidation.ts index 76951d6..1444b09 100644 --- a/src/lib/schemaValidation.ts +++ b/src/lib/schemaValidation.ts @@ -17,6 +17,134 @@ ajv.addFormat('web-url', { }); addErrors(ajv); +// Reusable [w] | [w,h] viewport tuple, bounds 320..7680 (ported from storybook validate.js) +const StorybookViewportTuple = { + type: "array", + oneOf: [ + { + items: [{ type: "integer", minimum: 320, maximum: 7680 }], + minItems: 1, + maxItems: 1 + }, + { + items: [ + { type: "integer", minimum: 320, maximum: 7680 }, + { type: "integer", minimum: 320, maximum: 7680 } + ], + minItems: 2, + maxItems: 2 + } + ], + errorMessage: "Invalid config; storybook viewport width/height must be >= 320 and <= 7680" +}; + +// storybook config block (ported from smartui-storybook validate.js rules) +const StorybookConfigBlock = { + type: "object", + properties: { + browsers: { + type: "array", + items: { type: "string", enum: constants.VALID_STORYBOOK_BROWSERS }, + minItems: 1, + uniqueItems: true, + errorMessage: { + minItems: "Invalid config; storybook browsers must have at least one entry", + uniqueItems: "Invalid config; storybook browsers must have unique entries", + _: `Invalid config; allowed storybook browsers - ${constants.VALID_STORYBOOK_BROWSERS.join(', ')}` + } + }, + viewports: { + type: "array", + minItems: 1, + maxItems: 5, + items: StorybookViewportTuple, + errorMessage: { + minItems: "Invalid config; storybook viewports must have at least one entry", + maxItems: "Invalid config; max storybook viewports allowed - 5" + } + }, + resolutions: { + type: "array", + minItems: 1, + maxItems: 5, + items: StorybookViewportTuple, + errorMessage: { + minItems: "Invalid config; storybook resolutions must have at least one entry", + maxItems: "Invalid config; max storybook resolutions allowed - 5" + } + }, + waitForTimeout: { + type: "integer", + minimum: 0, + maximum: 300000, + errorMessage: "Invalid config; storybook waitForTimeout must be >= 0 and <= 300000" + }, + include: { + type: "array", + items: { type: "string" } + }, + exclude: { + type: "array", + items: { type: "string" } + }, + customViewports: { + type: "array", + items: { + type: "object", + properties: { + stories: { type: "array", items: { type: "string" } }, + exclude: { type: "array", items: { type: "string" } }, + styles: { + type: "object", + properties: { + width: { type: "integer", minimum: 320, maximum: 7680 }, + height: { type: "integer", minimum: 320, maximum: 7680 } + }, + required: ["width"], + additionalProperties: false + }, + waitForTimeout: { type: "integer", minimum: 0, maximum: 300000 } + }, + // styles XOR waitForTimeout (one is required) + oneOf: [ + { required: ["styles"] }, + { required: ["waitForTimeout"] } + ], + // stories and exclude are mutually exclusive + not: { required: ["stories", "exclude"] }, + additionalProperties: false, + errorMessage: { + oneOf: "Invalid config; each customViewport must specify exactly one of styles or waitForTimeout", + not: "Invalid config; customViewport cannot specify both stories and exclude" + } + } + }, + useOnlyCustomViewports: { + type: "boolean", + errorMessage: "Invalid config; useOnlyCustomViewports must be true/false" + }, + backgroundTheme: { + type: "string", + enum: ["light", "dark", "both"], + errorMessage: "Invalid config; backgroundTheme must be light, dark or both" + }, + useGlobals: { + type: "boolean", + errorMessage: "Invalid config; useGlobals must be true/false" + }, + lazyLoadedStories: { + type: "array", + items: { type: "string" } + }, + chunkSize: { + type: "integer", + minimum: 1, + errorMessage: "Invalid config; chunkSize must be an integer >= 1" + } + }, + additionalProperties: false +}; + const ConfigSchema = { type: "object", properties: { @@ -389,11 +517,13 @@ const ConfigSchema = { showRenderErrors: { type: "boolean", errorMessage: "Invalid config; showRenderErrors must be true/false" - } + }, + storybook: StorybookConfigBlock }, anyOf: [ { required: ["web"] }, - { required: ["mobile"] } + { required: ["mobile"] }, + { required: ["storybook"] } ], additionalProperties: false } diff --git a/src/lib/tui.cjs b/src/lib/tui.cjs new file mode 100644 index 0000000..cfbb3cc --- /dev/null +++ b/src/lib/tui.cjs @@ -0,0 +1,85 @@ +// Pretty terminal-UI helpers for the SmartUI Storybook command. +// Uses figlet (banner), gradient-string (color), boxen (frames), chalk, log-symbols. +// Every helper degrades gracefully to plain text if a lib or a TTY is unavailable, +// so output is never broken in CI / piped contexts. + +let figlet, gradient, boxen, chalk, logSymbols; +try { figlet = require('figlet'); } catch (_) {} +try { gradient = require('gradient-string'); } catch (_) {} +try { boxen = require('boxen'); } catch (_) {} +try { chalk = require('chalk'); } catch (_) {} +try { logSymbols = require('log-symbols'); } catch (_) {} + +// SmartUI brand ramp — the visual-regression "diff magenta" into violet/cyan. +const RAMP = ['#c0286f', '#7b2ff7', '#2f9e8f']; +const paint = (s) => { + try { return gradient(RAMP)(s); } catch (_) { return s; } +}; +const dim = (s) => { try { return chalk.gray(s); } catch (_) { return s; } }; +const bold = (s) => { try { return chalk.bold(s); } catch (_) { return s; } }; + +function banner() { + let art; + try { + art = figlet.textSync('SmartUI', { font: 'ANSI Shadow', horizontalLayout: 'fitted' }); + } catch (_) { + art = null; + } + if (art) { + console.log('\n' + paint(art)); + } else { + console.log('\n' + paint('◆ SmartUI')); + } + console.log(dim(' Visual regression for Storybook · LambdaTest\n')); +} + +function box(title, lines, opts = {}) { + const body = lines.join('\n'); + const content = (title ? bold(title) + '\n\n' : '') + body; + if (!boxen) { console.log('\n' + content + '\n'); return; } + try { + console.log(boxen(content, { + padding: { top: 0, bottom: 0, left: 1, right: 1 }, + margin: { top: 1, bottom: 0, left: 0, right: 0 }, + borderStyle: 'round', + borderColor: opts.color || 'magenta', + title: opts.tag, + titleAlignment: 'left', + })); + } catch (_) { + console.log('\n' + content + '\n'); + } +} + +// key/value rows, aligned. +function kv(pairs) { + const w = Math.max(...pairs.map(([k]) => k.length)); + return pairs + .filter(([, v]) => v !== undefined && v !== null && v !== '') + .map(([k, v]) => `${dim((k + ':').padEnd(w + 2))} ${v}`); +} + +function runHeader({ target, mode, buildName, env, configPath, browsers, viewports, storyHint }) { + box('Storybook Visual Test', kv([ + ['Target', target], + ['Mode', mode === 'url' ? 'URL · live server (client render)' : 'DIR · static build (cloud render)'], + ['Build', buildName || dim('auto-generated')], + ['Env', env || 'prod'], + ['Config', configPath || dim('defaults')], + ['Browsers', browsers], + ['Viewports', viewports], + ['Stories', storyHint], + ]), { tag: ' launch ', color: 'magenta' }); +} + +function resultBox(ok, { buildUrl, message } = {}) { + const sym = logSymbols ? (ok ? logSymbols.success : logSymbols.error) : (ok ? '✔' : '✖'); + const head = ok ? paint('Storybook build submitted') : (chalk ? chalk.red('Storybook run failed') : 'Storybook run failed'); + const lines = []; + if (buildUrl) lines.push(kv([['Dashboard', buildUrl]])[0]); + if (message) lines.push(message); + if (!lines.length) lines.push(dim(ok ? 'Check the SmartUI dashboard for results.' : 'See the log above for details.')); + box(`${sym} ${head}`, lines, { tag: ok ? ' done ' : ' error ', color: ok ? 'green' : 'red' }); +} + +module.exports = { banner, box, kv, runHeader, resultBox, paint, dim, bold }; diff --git a/src/lib/tui.d.cts b/src/lib/tui.d.cts new file mode 100644 index 0000000..ee10cb5 --- /dev/null +++ b/src/lib/tui.d.cts @@ -0,0 +1,58 @@ +// Type surface for the terminal UI helpers. +// +// tui.cjs is CommonJS so that esbuild bundles it as CJS under the CLI's +// "type": "module", and so that it degrades gracefully when its optional +// pretty-printing dependencies are unavailable. Every function here is +// best-effort: none of them throw, and all of them no-op sensibly without a TTY. + +export interface RunHeaderInput { + target: string; + mode: 'url' | 'dir'; + buildName?: string; + env?: string; + configPath?: string; + browsers?: string; + viewports?: string; + storyHint?: string; +} + +export interface BoxOptions { + /** Short label rendered into the box border, e.g. ' done '. */ + tag?: string; + /** Border colour name understood by the underlying box renderer. */ + color?: string; +} + +export interface ResultBoxInput { + buildUrl?: string; + message?: string; +} + +/** Gradient figlet banner. No-ops when there is no TTY. */ +export declare function banner(): void; +/** Render a titled box around `lines`. */ +export declare function box(title: string, lines: string[], opts?: BoxOptions): void; +/** Format label/value pairs, skipping any pair whose value is null, undefined or empty. */ +export declare function kv(pairs: Array<[string, string | number | null | undefined]>): string[]; +/** Boxed summary of what this run is about to do. */ +export declare function runHeader(input: RunHeaderInput): void; +/** Terminal success/failure box. */ +export declare function resultBox(ok: boolean, input?: ResultBoxInput): void; +/** Apply the SmartUI gradient to a string, returning it unchanged on failure. */ +export declare function paint(s: string): string; +/** Dim a string, returning it unchanged on failure. */ +export declare function dim(s: string): string; +/** Bold a string, returning it unchanged on failure. */ +export declare function bold(s: string): string; + +declare const _default: { + banner: typeof banner; + box: typeof box; + kv: typeof kv; + runHeader: typeof runHeader; + resultBox: typeof resultBox; + paint: typeof paint; + dim: typeof dim; + bold: typeof bold; +}; +export default _default; diff --git a/src/storybookVendor/commands/config.cjs b/src/storybookVendor/commands/config.cjs new file mode 100644 index 0000000..d1daf47 --- /dev/null +++ b/src/storybookVendor/commands/config.cjs @@ -0,0 +1,29 @@ +const path = require('path'); +const fs = require('fs'); +const { defaultSmartUIConfig } = require('./utils/config.cjs'); +var { constants } = require('./utils/constants.cjs'); + +function createConfig(filepath) { + // default filepath + filepath = filepath || '.smartui.json'; + let filetype = path.extname(filepath); + if (filetype != '.json') { + console.log(`[smartui] Error: Config file must have .json extension`); + process.exitCode = constants.ERROR_CATCHALL; + return + } + + // verify the file does not already exist + if (fs.existsSync(filepath)) { + console.log(`[smartui] Error: LambdaTest SmartUI config already exists: ${filepath}`); + process.exitCode = constants.ERROR_CATCHALL; + return + } + + // write stringified default config options to the filepath + fs.mkdirSync(path.dirname(filepath), { recursive: true }); + fs.writeFileSync(filepath, JSON.stringify(defaultSmartUIConfig, null, 2) + '\n'); + console.log(`[smartui] Created LambdaTest SmartUI config: ${filepath}`); +}; + +module.exports = { createConfig }; \ No newline at end of file diff --git a/src/storybookVendor/commands/storybook.cjs b/src/storybookVendor/commands/storybook.cjs new file mode 100644 index 0000000..1cf71f7 --- /dev/null +++ b/src/storybookVendor/commands/storybook.cjs @@ -0,0 +1,261 @@ +const { httpClient } = require('./utils/httpClient.cjs') +const fs = require('fs') +const { sendDoM } = require('./utils/dom.cjs') +const { validateStorybookUrl, validateStorybookDir } = require('./utils/validate.cjs') +const { defaultSmartUIConfig } = require('./utils/config.cjs') +const { skipStory, normalizeStoryEntries } = require('./utils/story.cjs') +const { getLastCommit } = require('./utils/git.cjs') +const staticUtils = require('./utils/static.cjs') +var { constants } = require('./utils/constants.cjs'); +const { shortPolling } = require('./utils/polling.cjs'); + +// Resolve relative paths against a Storybook base URL. +// +// `new URL('index.json', 'http://host/sb')` yields 'http://host/index.json', because without a +// trailing slash the last segment is treated as a filename and replaced. A Storybook served under +// a sub-path (a reverse proxy, GitHub Pages, any /storybook/ deployment) is a normal thing to +// point this command at, and typing the URL without a trailing slash is the normal way to type it. +// Normalise once so every path below resolves under the base rather than beside it or at the root. +function storybookBase(url) { + const base = new URL(url); + if (!base.pathname.endsWith('/')) base.pathname += '/'; + return base; +} + +// Storybook >= 8 dropped stories.json in favour of index.json (entries keyed by story id). +// Try the modern file first and fall back to the legacy one so both generations work. +async function fetchStoryIndex(url) { + const base = storybookBase(url); + const candidates = ['index.json', 'stories.json']; + let lastError; + + for (const file of candidates) { + let response; + try { + response = await httpClient.get(new URL(file, base).href); + } catch (error) { + lastError = error; + continue; + } + + const data = response && response.data ? response.data : {}; + // Normalise before accepting a candidate: a served index.json can be a string or some + // other non-index payload (a proxy error page rendered as JSON, for example), and + // iterating that yields stories named "0", "1", "2" rather than a clean failure. + const entries = normalizeStoryEntries(data.entries || data.stories); + if (entries && Object.keys(entries).length) { + return { entries, source: file }; + } + lastError = new Error(`${file} did not contain any stories`); + } + + throw lastError || new Error(`neither ${candidates.join(' nor ')} could be read from ${url}`); +} + +async function storybook(serve, options) { + let type = /^https?:\/\//.test(serve) ? 'url' : 'dir'; + let storybookConfig = options.config ? options.config : defaultSmartUIConfig.storybook; + const buildName = options.buildName? options.buildName : ""; + + if (type === 'url') { + await validateStorybookUrl(serve); + let url = serve; + + // Convert browsers and resolutions arrays to string + let resolutions = []; + (storybookConfig.resolutions || storybookConfig.viewports || []).forEach(element => { + resolutions.push(element.join('x')); + }); + storybookConfig.resolutions = (!resolutions.length) ? 'all' : resolutions.toString(); + storybookConfig.browsers = (!storybookConfig.browsers.length) ? 'all' : storybookConfig.browsers.map(x => x.toLowerCase()).toString(); + + // Get the story index and add url corresponding to every story ID. + // Storybook >= 8 serves index.json; older versions serve stories.json. + let index; + try { + index = await fetchStoryIndex(url); + } catch (error) { + process.exitCode = constants.ERROR_CATCHALL; + console.log('[smartui] Cannot fetch stories. Error: ', error.message); + return; + } + console.log(`[smartui] Story index read from ${index.source}`); + + let stories = {} + for (const [storyId, storyInfo] of Object.entries(index.entries)) { + if (!skipStory(storyInfo, storybookConfig)) { + stories[storyId] = { + name: storyInfo.name, + kind: storyInfo.kind || storyInfo.title, + url: new URL('iframe.html?id=' + storyId + '&viewMode=story', storybookBase(url)).href + } + } + } + + if (Object.keys(stories).length === 0) { + console.log('[smartui] Error: No stories found'); + process.exit(constants.ERROR_CATCHALL); + } + console.log('[smartui] Stories found: ', Object.keys(stories).length); + console.log('[smartui] Number of stories rendered may differ based on the config file.'); + + // Capture DoM of every story and send it to renderer API + await sendDoM(url, stories, storybookConfig, options); + } else { + let dirPath = serve; + await validateStorybookDir(dirPath); + + // Get storyIds to be rendered + let storyIds = staticUtils.filterStories(dirPath, storybookConfig) + let maxStories = storybookConfig.chunkSize || 100; + let lazyLoadedStories = []; + if (Array.isArray(storybookConfig.lazyLoadedStories) && storybookConfig.lazyLoadedStories.length > 0) { + lazyLoadedStories = storybookConfig.lazyLoadedStories; + } + let useGlobals = false; + let backgroundTheme = storybookConfig.backgroundTheme || 'light'; + if (storybookConfig.backgroundTheme && ['light', 'dark'].includes(storybookConfig.backgroundTheme.toLowerCase())) { + useGlobals = true; + backgroundTheme = storybookConfig.backgroundTheme.toLowerCase(); + } + + if (storybookConfig.useGlobals === true || storybookConfig.backgroundTheme == undefined) { + useGlobals = true; + backgroundTheme = 'light'; + } + + // Upload Storybook static + await staticUtils.getSignedUrl(options) + .then(async function (response) { + let { url, uploadId } = response.data.data; + + // Compress static build + await staticUtils.compress(dirPath, uploadId) + .then(function () { + console.log(`[smartui] ${dirPath} compressed.`) + }) + .catch(function (err) { + console.log(`[smartui] Cannot compress ${dirPath}. Error: ${err.message}`); + process.exit(constants.ERROR_CATCHALL); + }); + + // Upload to S3 + const zipData = fs.readFileSync('storybook-static.zip'); + console.log('[smartui] Upload in progress...') + await httpClient.put(url, zipData, { + headers: { + 'Content-Type': 'application/zip', + 'Content-Length': zipData.length + }}) + .then(function (response) { + console.log(`[smartui] ${dirPath} uploaded.`); + fs.rmSync('storybook-static.zip'); + }) + .catch(function (error) { + console.log(`[smartui] Cannot upload ${dirPath}. Error: ${error.message}`); + fs.rmSync('storybook-static.zip'); + process.exit(constants.ERROR_CATCHALL); + }); + + // Prepare payload data + let browsers = [] + let resolutions = [] + + storybookConfig.browsers.forEach(element => { + browsers.push(element.toLowerCase()); + }); + let rs = storybookConfig.resolutions || storybookConfig.viewports + if (rs && rs.length){ + rs.forEach(element => { + resolutions.push({ width: element[0], height: element[1] }); + }); + } + + let commit = await getLastCommit(); + let baseLine = process.env.BASELINE_BRANCH; + let currentBranch = process.env.CURRENT_BRANCH; + if (baseLine !== null && baseLine !== undefined){ + if(baseLine === ''){ + const error = { + "error": "MISSING_BRANCH_NAME", + "message": "Error : The baseline branch name environment variable cannot be empty." + }; + console.log(JSON.stringify(error, null, 2)); + process.exit(1); + } + } + + if(currentBranch !== null && currentBranch !==undefined){ + if(currentBranch === ''){ + const error = { + "error": "MISSING_BRANCH_NAME", + "message": "Error : The current branch name environment variable cannot be empty." + }; + console.log(JSON.stringify(error, null, 2)); + process.exit(1); + } + } + let payload = { + downloadURL: url.substring(url.search(/.com/)+5, url.search(/.zip/)+4), + uploadId: uploadId, + projectToken: process.env.PROJECT_TOKEN, + storybookConfig: { + browsers: browsers, + resolutions: resolutions, + storyIds: storyIds, + waitForTimeout: storybookConfig.waitForTimeout, + customViewports: storybookConfig.customViewports, + useOnlyCustomViewports: storybookConfig.useOnlyCustomViewports, + lazyLoadedStories: lazyLoadedStories, + useGlobals: useGlobals, + backgroundTheme: backgroundTheme + }, + git: { + branch: currentBranch || commit.branch|| '', + baselineBranch: baseLine || '', + commitId: commit.shortHash, + commitAuthor: commit.author.name, + commitMessage: commit.subject, + githubURL: process.env.GITHUB_URL || '', + }, + buildName: buildName, + tunnel: options.tunnel || {}, + maxStories: maxStories + } + + // Call static render API + await httpClient.post(new URL(constants[options.env].STATIC_RENDER_PATH, constants[options.env].BASE_URL).href, payload) + .then(async function (response) { + if (response.data && response.data.error) { + console.log('[smartui] Error: ', response.data.error.message); + process.exitCode = constants.ERROR_CATCHALL; + return + } + console.log('[smartui] Build URL: ', response.data.data.buildURL); + console.log('[smartui] Build in progress...'); + await shortPolling(response.data.data.buildId, 0, options); + }) + .catch(function (error) { + if (error.response) { + console.log('[smartui] Build failed: Error: ', error.response.data.error?.message); + } else { + console.log('[smartui] Build failed: Error: ', error.message); + } + process.exitCode = constants.ERROR_CATCHALL; + }); + }) + .catch(function (error) { + if (error.response) { + console.log('[smartui] Error: ', error.response.data.error?.message); + } else { + console.log('[smartui] Error: ', error.message); + } + process.exitCode = constants.ERROR_CATCHALL; + }); + + } +}; + +// fetchStoryIndex is exported for tests: it is the TE-24909 fix (Storybook >= 8 index.json +// discovery with a legacy stories.json fallback) and is worth covering directly. +module.exports = { storybook, fetchStoryIndex, storybookBase }; \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/config.cjs b/src/storybookVendor/commands/utils/config.cjs new file mode 100644 index 0000000..9794837 --- /dev/null +++ b/src/storybookVendor/commands/utils/config.cjs @@ -0,0 +1,19 @@ +const defaultSmartUIConfig = { + storybook: { + browsers: [ + 'chrome', + 'firefox', + 'safari', + 'edge' + ], + viewports: [ + [1920, 1080] + ], + waitForTimeout: 0, + include: [], + exclude: [], + customViewports: [] + } +}; + +module.exports = { defaultSmartUIConfig } \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/constants.cjs b/src/storybookVendor/commands/utils/constants.cjs new file mode 100644 index 0000000..ed0b972 --- /dev/null +++ b/src/storybookVendor/commands/utils/constants.cjs @@ -0,0 +1,32 @@ +var constants = {} + +constants.stage = { + AUTH_URL: "https://stage-api.lambdatestinternal.com/storybook/auth", + RENDER_API_URL: "https://stage-api.lambdatestinternal.com/storybook/render", + BUILD_STATUS_URL: "https://stage-api.lambdatestinternal.com/storybook/status", + BASE_URL: "https://stage-api.lambdatestinternal.com", + SB_BUILD_VALIDATE_PATH: "/storybook/validate", + CHECK_UPDATE_PATH: "storybook/packageinfo", + GET_SIGNED_URL_PATH: "/storybook/url", + STATIC_RENDER_PATH: "/storybook/staticrender", + TOKEN_VERIFY_URL: "https://stage-api.lambdatestinternal.com/visualui/1.0/token/verify" +}; +constants.prod = { + AUTH_URL: "https://api.lambdatest.com/storybook/auth", + RENDER_API_URL: "https://api.lambdatest.com/storybook/render", + BUILD_STATUS_URL: "https://api.lambdatest.com/storybook/status", + BASE_URL: "https://api.lambdatest.com", + SB_BUILD_VALIDATE_PATH: "/storybook/validate", + CHECK_UPDATE_PATH: "storybook/packageinfo", + GET_SIGNED_URL_PATH: "/storybook/url", + STATIC_RENDER_PATH: "/storybook/staticrender", + TOKEN_VERIFY_URL: "https://api.lambdatest.com/visualui/1.0/token/verify" +}; +constants.VALID_BROWSERS = ['chrome', 'safari', 'firefox', 'edge']; + +// Error codes +constants.ERROR_CATCHALL = 1 +constants.ERROR_BUILD_ALREADY_EXISTS = 3 +constants.ERROR_CHANGES_FOUND_OR_REJECTED = 4 + +module.exports = { constants }; \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/dom.cjs b/src/storybookVendor/commands/utils/dom.cjs new file mode 100644 index 0000000..5774f92 --- /dev/null +++ b/src/storybookVendor/commands/utils/dom.cjs @@ -0,0 +1,143 @@ +const { httpClient } = require('./httpClient.cjs'); +const fs = require('fs'); +const path = require('path') +const formData = require('form-data'); +const { JSDOM } = require("jsdom"); +var { constants } = require('./constants.cjs'); +const { getLastCommit } = require('./git.cjs'); +const { shortPolling } = require('./polling.cjs'); +const puppeteer = require('puppeteer'); + +async function sendDoM(storybookUrl, stories, storybookConfig, options) { + let browser; + try { + browser = await puppeteer.launch({ + headless: 'new', + args: ['--no-sandbox', '--disable-setuid-sandbox'], + }); + } catch (error) { + // The usual cause is a missing Chromium download: package managers that skip + // install scripts (pnpm >= 10 by default) never run puppeteer's postinstall, + // so launch times out waiting for a browser that was never fetched. + console.log('[smartui] Error: Cannot launch the browser used to capture stories.'); + console.log('[smartui] Error: ', error.message.split('\n')[0]); + console.log("[smartui] If Chromium is missing, install it with 'npx puppeteer browsers install chrome'."); + process.exit(constants.ERROR_CATCHALL); + } + + if (!fs.existsSync('doms')){ + fs.mkdir('doms', (err) => { + if (err) { + console.error(err); + process.exit(constants.ERROR_CATCHALL); + } + }); + } + for (const [storyId, storyInfo] of Object.entries(stories)) { + const page = await browser.newPage(); + await page.goto(storyInfo.url, { waitUntil: 'networkidle0' }); + const html = await page.content(); + + const dom = new JSDOM(html, { + url: storybookUrl, + resources: 'usable' + }); + const clone = new JSDOM(html); + + // Serialize DOM + for(const element of clone.window.document.querySelectorAll('img')) { + let image = new URL(element.getAttribute('src'), storybookUrl).href; + let format = path.extname(image).replace(/^./, ''); + format = format === 'svg' ? 'svg+xml' : format + let imageAsBase64 = await getBase64(image); + element.setAttribute('src', 'data:image/'+format+';base64,'+imageAsBase64); + } + await serializeCSSOM(dom, clone); + + try { + fs.writeFileSync('doms/' + storyId + '.html', clone.serialize()); + } catch (err) { + console.error(err); + } + + await page.close(); + } + await browser.close() + + // Create form + let commit = await getLastCommit(); + const form = new formData(); + for (const [storyId, storyInfo] of Object.entries(stories)) { + const file = fs.readFileSync('doms/' + storyId + '.html'); + let title = storyInfo.kind || storyInfo.title; + title = title ? title.replaceAll('/', '#')+': ' : ''; + let filename = title + storyInfo.name; + form.append('files', file, filename+'.html'); + } + form.append('resolution', storybookConfig.resolutions); + form.append('browser', storybookConfig.browsers); + form.append('projectToken', process.env.PROJECT_TOKEN); + form.append('branch', commit.branch); + form.append('commitId', commit.shortHash); + form.append('commitAuthor', commit.author.name); + form.append('commitMessage', commit.subject); + form.append('customViewports', JSON.stringify(storybookConfig.customViewports)); + let githubURL = process.env.GITHUB_URL + if (githubURL) { + form.append('githubURL', githubURL); + } + + // Send DOM to render API + await httpClient.post(constants[options.env].RENDER_API_URL, form, { + headers: { + ...form.getHeaders() + } + }) + .then(async function (response) { + console.log('[smartui] Build URL: ', response.data.buildURL); + console.log('[smartui] Build in progress...'); + await shortPolling(response.data.buildId, 0, options); + }) + .catch(function (error) { + if (error.response) { + console.log('[smartui] Build failed: Error: ', error.response.data.message); + } else { + console.log('[smartui] Build failed: Error: ', error.message); + } + }); + + fs.rm('doms', {recursive: true}, (err) => { + if (err) { + return console.error(err); + } + }); +}; + +function getBase64(url) { + return httpClient.get(url, { + responseType: "text", + responseEncoding: "base64", + }) + .then(response => response.data) + .catch(function (error) { + console.log('[smartui] Error: ', error.message); + process.exit(constants.ERROR_CATCHALL); + }); +} + +async function serializeCSSOM(dom, clone) { + return new Promise(resolve => { + dom.window.addEventListener("load", () => { + for (let styleSheet of dom.window.document.styleSheets) { + let style = clone.window.document.createElement('style'); + style.type = 'text/css'; + style.innerHTML = Array.from(styleSheet.cssRules) + .map(cssRule => cssRule.cssText).join('\n'); + clone.window.document.head.appendChild(style); + } + resolve(); + }); + }); +} + +module.exports = { sendDoM }; diff --git a/src/storybookVendor/commands/utils/git.cjs b/src/storybookVendor/commands/utils/git.cjs new file mode 100644 index 0000000..4c32e85 --- /dev/null +++ b/src/storybookVendor/commands/utils/git.cjs @@ -0,0 +1,58 @@ +const cp = require('child_process'); + +function executeCommand(command, options) { + let dst = process.cwd() + + if(!!options && options.dst) { + dst = options.dst + } + + try { + return cp.execSync(command, { + cwd: dst, + stdio: ['ignore', 'pipe', 'ignore'], + encoding: 'utf-8' + }); + } catch (error) { + return ''; + } +} + +async function getLastCommit(options) { + const splitCharacter = '<##>'; + const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""]; + const command = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '"' + + ' && git rev-parse --abbrev-ref HEAD' + + ' && git tag --contains HEAD' + + let res = executeCommand(command, options); + res = res.split(splitCharacter); + + // e.g. master\n or master\nv1.1\n or master\nv1.1\nv1.2\n + var branchAndTags = res[res.length-1].split('\n').filter(n => n); + var branch = branchAndTags[0]; + var tags = branchAndTags.slice(1); + + return { + shortHash: res[0] || '', + hash: res[1] || '', + subject: res[2] || '', + sanitizedSubject: res[3] || '', + body: res[4] || '', + authoredOn: res[5] || '', + committedOn: res[6] || '', + author: { + name: res[7] || '', + email: res[8] || '', + }, + committer: { + name: res[9] || '', + email: res[10] || '' + }, + notes: res[11] || '', + branch: branch || '', + tags: tags || [] + }; +} + +module.exports = { getLastCommit } \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/httpClient.cjs b/src/storybookVendor/commands/utils/httpClient.cjs new file mode 100644 index 0000000..4ee27ae --- /dev/null +++ b/src/storybookVendor/commands/utils/httpClient.cjs @@ -0,0 +1,39 @@ +const axios = require('axios'); +const https = require('https'); +const { HttpsProxyAgent } = require('https-proxy-agent'); +const { HttpProxyAgent } = require('http-proxy-agent'); + +let proxyUrl = null; + +try { + const SMARTUI_API_PROXY = process.env.SMARTUI_API_PROXY; + if (SMARTUI_API_PROXY) { + const urlStr = SMARTUI_API_PROXY.startsWith('http') ? + SMARTUI_API_PROXY : `http://${SMARTUI_API_PROXY}`; + proxyUrl = new URL(urlStr); + } +} catch (error) { + console.error('[smartui] Invalid proxy URL:', error.message); +} + +const skipCertificates = process.env.SMARTUI_API_SKIP_CERTIFICATES === 'true'; + +const axiosConfig = {}; + +if (proxyUrl) { + const agentOptions = { + rejectUnauthorized: !skipCertificates + }; + + axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl, agentOptions); + axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl,agentOptions); +} else if (skipCertificates) { + axiosConfig.httpsAgent = new https.Agent({ + rejectUnauthorized: false + }); +} + +const httpClient = axios.create(axiosConfig); + +module.exports = { httpClient }; + diff --git a/src/storybookVendor/commands/utils/package.cjs b/src/storybookVendor/commands/utils/package.cjs new file mode 100644 index 0000000..f9ed54d --- /dev/null +++ b/src/storybookVendor/commands/utils/package.cjs @@ -0,0 +1,29 @@ +var { constants } = require('./constants.cjs'); +const { httpClient } = require('./httpClient.cjs'); + +// Check for package updates +function checkUpdate(version, options) { + return httpClient.get(new URL(constants[options.env].CHECK_UPDATE_PATH, constants[options.env].BASE_URL).href, { + params: { + packageName: 'smartui-storybook', + packageVersion: version + }}) + .then(function (response) { + if (response.data.data.deprecated) { + console.log('v' + version + ' is deprecated. Please update to v' + response.data.data.latestVersion); + } else if (response.data.data.latestVersion != version) { + console.log('A newer version v' + response.data.data.latestVersion + ' is available.'); + } + }) + .catch(function (error) { + if (error.response && error.response.data && error.response.data.error) { + console.log('Cannot check for updates. Error: ' + error.response.data.error.message); + } else if (error.code) { + console.log('Cannot check for updates. Error: ' + error.code + (error.message ? ' - ' + error.message : '')); + } else { + console.log('Cannot check for updates. Error: ' + (error.message || JSON.stringify(error))); + } + }); +}; + +module.exports = { checkUpdate }; \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/polling.cjs b/src/storybookVendor/commands/utils/polling.cjs new file mode 100644 index 0000000..e5366b3 --- /dev/null +++ b/src/storybookVendor/commands/utils/polling.cjs @@ -0,0 +1,97 @@ +const { httpClient } = require('./httpClient.cjs'); +const Table = require('cli-table3'); +var { constants } = require('./constants.cjs'); + +var INTERVAL = 2000 +const MAX_EXPONENTIAL_INTERVAL = 512000 // 512 seconds (8.5 minutes) +const FIXED_INTERVAL = 60000 // 1 minute in milliseconds +const MAX_INTERVAL = 1800000; // 30 minutes in milliseconds +var CURRENT_TIME = 0 +var FLAG = 0 + +async function shortPolling(buildId, retries = 0, options) { + await httpClient.get(new URL('?buildId=' + buildId, constants[options.env].BUILD_STATUS_URL).href, { + headers: { + projectToken: process.env.PROJECT_TOKEN + }}) + .then(function (response) { + if (response.data) { + if (response.data.buildStatus === 'completed') { + console.log('[smartui] Build successful\n'); + console.log('[smartui] Build details:\n', + 'Build URL: ', response.data.buildURL, '\n', + 'Build ID: ', buildId, '\n', + 'Build Name: ', response.data.buildName, '\n', + 'Total Screenshots: ', response.data.totalScreenshots, '\n', + 'Approved: ', response.data.buildResults.approved, '\n', + 'Changes found: ', response.data.buildResults.changesFound, '\n', + 'Rejected:' , response.data.buildResults.rejected, '\n' + ); + + if (response.data.screenshots && response.data.screenshots.length > 0) { + import('chalk').then((chalk) => { + const table = new Table({ + head: [ + {content: chalk.default.white('Sr. Number'), hAlign: 'center'}, + {content: chalk.default.white('Story'), hAlign: 'center'}, + {content: chalk.default.white('Mis-match %'), hAlign: 'center'}, + ] + }); + response.data.screenshots.forEach((screenshot, index) => { + let mismatch = screenshot.mismatchPercentage; + table.push([ + chalk.default.yellow(index + 1), + chalk.default.yellow(screenshot.storyName), + mismatch > 0 ? chalk.default.red(mismatch) : chalk.default.green(mismatch) + ]); + }); + console.log(table.toString()); + }) + } else { + if (response.data.baseline) { + console.log('No comparisons run. This is a baseline build.'); + } else { + console.log('No comparisons run. No screenshot in the current build has the corresponding screenshot in baseline build.'); + } + } + return; + } else { + if (response.data.screenshots && response.data.screenshots.length > 0) { + // TODO: show Screenshots processed current/total + console.log('[smartui] Screenshots compared: ', response.data.screenshots.length) + } + } + } + + CURRENT_TIME = CURRENT_TIME + INTERVAL + if (CURRENT_TIME >= MAX_INTERVAL) { + console.log('[smartui] Please check the build status on LambdaTest SmartUI.'); + return; + } + + // Adjust the interval + if (Math.min(INTERVAL * 2, MAX_EXPONENTIAL_INTERVAL) < MAX_EXPONENTIAL_INTERVAL && FLAG == 0) { + INTERVAL = Math.min(INTERVAL * 2, MAX_EXPONENTIAL_INTERVAL); + } else { + FLAG = 1 + INTERVAL = FIXED_INTERVAL; // Switch to fixed interval after reaching 256 seconds + } + + setTimeout(function () { + shortPolling(buildId, 0, options) + }, INTERVAL); + }) + .catch(function (error) { + if (retries >= 3) { + console.log('[smartui] Error: Failed getting build status.', error.message); + console.log('[smartui] Please check the build status on LambdaTest SmartUI.'); + return; + } + + setTimeout(function () { + shortPolling(buildId, retries+1, options); + }, 2000); + }); +}; + +module.exports = { shortPolling } \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/redact.cjs b/src/storybookVendor/commands/utils/redact.cjs new file mode 100644 index 0000000..7d99fd0 --- /dev/null +++ b/src/storybookVendor/commands/utils/redact.cjs @@ -0,0 +1,36 @@ +// Strip credentials out of anything before it is printed. +// +// The backend echoes the caller's credentials in at least one error message: a failed +// /visualui/1.0/token/verify answers with "Authentication failed for provided username: +// and accessKey: ". Printing a server message verbatim therefore wrote a +// live access key to stdout, and from there into CI logs and anywhere they are shipped. +// +// Redaction happens on the way out rather than at each call site, because the leak is in data we +// do not control and new messages appear whenever the backend changes. + +// Long opaque tokens LambdaTest issues, e.g. LT_xxxxxxxx... +const ACCESS_KEY_PATTERN = /\bLT_[A-Za-z0-9_-]{16,}\b/g; +// The composite project token shape: orgId#ULID#projectName +const COMPOSITE_TOKEN_PATTERN = /\b\d{4,}#[0-9A-HJKMNP-TV-Z]{26}#[^\s"',]+/g; + +function escapeRegExp(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function redact(value) { + if (typeof value !== 'string' || !value) return value; + let out = value; + + // Exact values first: these catch key shapes the patterns below do not anticipate. + for (const secret of [process.env.LT_ACCESS_KEY, process.env.PROJECT_TOKEN]) { + if (secret && secret.length >= 8) { + out = out.replace(new RegExp(escapeRegExp(secret), 'g'), '[REDACTED]'); + } + } + + out = out.replace(ACCESS_KEY_PATTERN, '[REDACTED]'); + out = out.replace(COMPOSITE_TOKEN_PATTERN, '[REDACTED]'); + return out; +} + +module.exports = { redact }; diff --git a/src/storybookVendor/commands/utils/static.cjs b/src/storybookVendor/commands/utils/static.cjs new file mode 100644 index 0000000..5562607 --- /dev/null +++ b/src/storybookVendor/commands/utils/static.cjs @@ -0,0 +1,100 @@ +const fs = require('fs'); +const { httpClient } = require('./httpClient.cjs'); +const archiver = require('archiver'); +var { constants } = require('./constants.cjs'); +const { skipStory, normalizeStoryEntries } = require('./story.cjs'); +const { shortPolling } = require('./polling.cjs'); + +var INTERVAL = 2000 +const MAX_INTERVAL = 512000 + +function getSignedUrl(options) { + return httpClient.get(new URL(constants[options.env].GET_SIGNED_URL_PATH, constants[options.env].BASE_URL).href, { + headers: { + projectToken: process.env.PROJECT_TOKEN + }}); +} + +async function compress(dirPath, uploadId) { + return new Promise(function (resolve, reject) { + // create a file to stream archive data to. + const output = fs.createWriteStream('storybook-static.zip', {autoClose: true, emitClose: false}); + const archive = archiver('zip', { + zlib: { level: 9 } // Sets the compression level. + }); + + output.on('end', function() { + console.log('Data has been drained'); + }); + + output.on('finish', function() { + resolve(); + }); + + // Catch warnings (ie stat failures and other non-blocking errors) + archive.on('warning', function(err) { + if (err.code === 'ENOENT') { + console.log('Warning: ', err) + } else { + reject(err) + } + }); + + // Catch errors + archive.on('error', function(err) { + reject(err); + }); + + // pipe archive data to the file + archive.pipe(output); + // append files from a sub-directory and naming it `new-subdir` within the archive + archive.directory(dirPath, uploadId); + archive.finalize(); + }); +} + +function filterStories(dirPath, storybookConfig) { + let storyIds = []; + let stories = [] + // Prefer index.json, matching URL-mode discovery in storybook.cjs (TE-24909). + // Storybook >= 8 writes index.json; a stories.json sitting next to it is a leftover + // from an older build of the same directory, and reading that instead would give DIR + // mode a different story set from URL mode against the same Storybook. + let indexFile; + if (fs.existsSync((`${dirPath}/index.json`))){ + indexFile = `${dirPath}/index.json`; + } else if(fs.existsSync((`${dirPath}/stories.json`))){ + indexFile = `${dirPath}/stories.json`; + } + + if (indexFile) { + let index; + try { + index = JSON.parse(fs.readFileSync(indexFile)); + } catch (error) { + console.log(`[smartui] Error: Could not parse ${indexFile}: ${error.message}`); + process.exit(constants.ERROR_CATCHALL); + } + stories = normalizeStoryEntries(index && (index.entries || index.stories)); + if (!stories) { + console.log(`[smartui] Error: ${indexFile} does not contain a story index`); + process.exit(constants.ERROR_CATCHALL); + } + } + + for (const [storyId, storyInfo] of Object.entries(stories)) { + if (!skipStory(storyInfo, storybookConfig)) { + storyIds.push(storyId); + } + } + if (storyIds.length === 0) { + console.log('[smartui] Error: No stories found'); + process.exit(constants.ERROR_CATCHALL); + } + console.log('[smartui] Stories found: ', storyIds.length); + console.log('[smartui] Number of stories rendered may differ based on the config file.'); + + return storyIds +} + +module.exports = { getSignedUrl, compress, filterStories }; diff --git a/src/storybookVendor/commands/utils/story.cjs b/src/storybookVendor/commands/utils/story.cjs new file mode 100644 index 0000000..49618bc --- /dev/null +++ b/src/storybookVendor/commands/utils/story.cjs @@ -0,0 +1,52 @@ +// A story index is only usable if it is a plain object whose values are objects. Returns the +// entries, or null when the payload is not a story index at all. +// +// Guarding this is not theoretical. A truncated or hand-edited index.json can carry +// `entries: null`, no `entries` key, or a bare string, and each used to fail differently and +// badly: the first two crashed with a raw TypeError ("Cannot convert undefined or null to +// object"), and a string was iterated by character index, producing stories called "0", "1", +// "2", "3" that were then uploaded to the backend as if they were real. +function normalizeStoryEntries(raw) { + if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null; + const entries = {}; + for (const [id, story] of Object.entries(raw)) { + // Junk entries are dropped rather than crashing the run. If that empties the index the + // caller's "No stories found" path reports it cleanly. + if (story && typeof story === 'object' && !Array.isArray(story)) entries[id] = story; + } + return entries; +} + +// Returns true or false if the story should be skipped based on include and exclude config +function skipStory(story, config) { + // Defensive: callers normalise first, but skipStory is also called directly. + if (!story || typeof story !== 'object') return true; + + // skip story if it's docs for version 7 + if (story.parameters && story.parameters.docsOnly) { + return true; + } + + // skip story if it's docs for version 8 + if(story.type && story.type === 'docs'){ + return true; + } + + let matches = regexp => { + if (typeof regexp === 'string') { + let [, parsed, flags] = /^\/(.+)\/(\w+)?$/.exec(regexp) || []; + regexp = new RegExp(parsed ?? regexp, flags); + } + + return regexp?.test?.(story.name); + }; + + let include = [].concat(config?.include).filter(Boolean); + let exclude = [].concat(config?.exclude).filter(Boolean); + + let skip = include?.length ? !include.some(matches) : false; + if (!skip && !exclude?.some(matches)) return false; + return true; +}; + +module.exports = { skipStory, normalizeStoryEntries }; \ No newline at end of file diff --git a/src/storybookVendor/commands/utils/validate.cjs b/src/storybookVendor/commands/utils/validate.cjs new file mode 100644 index 0000000..b5c5679 --- /dev/null +++ b/src/storybookVendor/commands/utils/validate.cjs @@ -0,0 +1,347 @@ +const { httpClient } = require('./httpClient.cjs'); +var { constants } = require('./constants.cjs'); +const { redact } = require('./redact.cjs'); +const fs = require('fs'); +const { getLastCommit } = require('./git.cjs'); + +const MAX_RESOLUTIONS = 5 +const MIN_RESOLUTION_WIDTH = 320 +const MIN_RESOLUTION_HEIGHT = 320 +const MAX_RESOLUTION_WIDTH = 7680 +const MAX_RESOLUTION_HEIGHT = 7680 + +class ValidationError extends Error { + constructor(message) { + super(message); + this.name = 'ValidationError'; + } +} + +// Resolve PROJECT_NAME into a project token the same way the core CLI does, so +// `smartui storybook` accepts PROJECT_NAME (auto-creating the project) and is not +// limited to a pre-issued PROJECT_TOKEN. +async function resolveProjectToken(options) { + const { PROJECT_NAME, LT_USERNAME, LT_ACCESS_KEY } = process.env; + + if (!LT_USERNAME || !LT_ACCESS_KEY) { + console.log('[smartui] Error: PROJECT_NAME requires LT_USERNAME and LT_ACCESS_KEY to be set'); + process.exit(constants.ERROR_CATCHALL); + } + + let response; + try { + response = await httpClient.get(constants[options.env].TOKEN_VERIFY_URL, { + headers: { + projectName: PROJECT_NAME, + userName: LT_USERNAME, + accessKey: LT_ACCESS_KEY + } + }); + } catch (error) { + const errorMsg = redact(error.response + ? (error.response.data && error.response.data.message) || error.message + : error.message); + console.log(`[smartui] Error: Cannot resolve PROJECT_NAME '${PROJECT_NAME}'. Error: `, errorMsg); + process.exit(constants.ERROR_CATCHALL); + } + + const body = (response.data && response.data.data) || response.data || {}; + if (!body.projectToken) { + // /token/verify answers 200 even when project creation fails, carrying the reason in + // the body rather than the status code. Print that reason: saying only "token not + // received" sends people hunting for a credentials problem when the server has + // already told us it was something else, e.g. a 502 from project creation. + const reason = redact(body.message || (response.data && response.data.message)); + console.log(`[smartui] Error: Cannot resolve PROJECT_NAME '${PROJECT_NAME}'.` + (reason ? ` Error: ${reason}` : ' No project token was returned.')); + process.exit(constants.ERROR_CATCHALL); + } + + process.env.PROJECT_TOKEN = body.projectToken; + if (body.message && body.message.includes('Project created successfully')) { + console.log(`[smartui] Project '${PROJECT_NAME}' created`); + } + console.log(`[smartui] Resolved PROJECT_NAME '${PROJECT_NAME}' to a project token`); +} + +async function validateProjectToken(options) { + if (!process.env.PROJECT_TOKEN && process.env.PROJECT_NAME) { + await resolveProjectToken(options); + } + + if (process.env.PROJECT_TOKEN) { + return httpClient.get(constants[options.env].AUTH_URL, { + headers: { + projectToken: process.env.PROJECT_TOKEN + } + }) + .then(function (response) { + console.log('[smartui] Project Token Validated'); + }) + .catch(function (error) { + if (error.response) { + console.log('[smartui] Error: Invalid Project Token'); + } else if (error.request) { + const errorMsg = error.code ? `${error.code}${error.message ? ' - ' + error.message : ''}` : (error.message || 'Unknown error'); + console.log('[smartui] Project Token not validated. Error: ', errorMsg); + } else { + const errorMsg = error.code ? `${error.code}${error.message ? ' - ' + error.message : ''}` : (error.message || 'Unknown error'); + console.log('[smartui] Project Token not validated. Error: ', errorMsg); + } + process.exit(constants.ERROR_CATCHALL); + }); + } + + console.log('[smartui] Error: No PROJECT_TOKEN or PROJECT_NAME set'); + process.exit(constants.ERROR_CATCHALL); +}; + +function validateStorybookUrl(url) { + let aboutUrl; + try { + aboutUrl = new URL('?path=/settings/about', url).href; + } catch (error) { + console.log('[smartui] Error: ', error.message) + process.exit(constants.ERROR_CATCHALL); + } + return httpClient.get(aboutUrl) + .then(function (response) { + console.log('[smartui] Connection to storybook established'); + }) + .catch(function (error) { + if (error.response) { + console.log('[smartui] Connection to storybook not established. Error: ', error.message); + } else if (error.request) { + console.log('[smartui] Connection to storybook not established. Error: ', error.message); + } else { + console.log('[smartui] Connection to storybook not established. Error: ', error.message); + } + process.exit(constants.ERROR_CATCHALL); + }); +}; + +async function validateStorybookDir(dir) { + // verify the directory exists + if (!fs.existsSync(dir)) { + console.log(`[smartui] Error: No directory found: ${dir}`); + process.exit(constants.ERROR_CATCHALL); + } + // Verify project.json and stories.json exist to confirm it's a storybook-static dir + if (!fs.existsSync(dir + '/index.html')) { + console.log(`[smartui] Given directory is not a storybook static directory. Error: No index.html found`); + process.exit(constants.ERROR_CATCHALL); + } + if (!fs.existsSync(dir + '/stories.json') && !fs.existsSync(dir + '/index.json')) { + console.log(`[smartui] Given directory is not a storybook static directory. Error: stories.json or index.json not found`); + process.exit(constants.ERROR_CATCHALL); + } + +}; + +async function validateLatestBuild(options) { + let commit = await getLastCommit(); + + // Build de-duplication keys off branch + commit. Outside a git repo there is nothing + // to de-duplicate against, and sending empty keys makes the API reject the request with + // an error that reads like an auth failure. Skip the check instead, matching how the + // core CLI skips "Fetching git repo details" when it is not a git repo. + if (!commit.branch || !commit.shortHash) { + console.log('[smartui] Not a git repository; skipping duplicate-build check.'); + console.log('[smartui] Run inside a git repo to enable build de-duplication by branch and commit.'); + return; + } + + return httpClient.get(new URL(constants[options.env].SB_BUILD_VALIDATE_PATH, constants[options.env].BASE_URL).href, { + headers: { + projectToken: process.env.PROJECT_TOKEN + }, + params: { + branch: commit.branch, + commitId: commit.shortHash + } + }) + .then(function (response) { + if (response.data.status === 'Failure') { + console.log(`[smartui] Build with commit '${commit.shortHash}' on branch '${commit.branch}' already exists.`); + console.log('[smartui] Use option --force-rebuild to forcefully push a new build.'); + process.exit(constants.ERROR_BUILD_ALREADY_EXISTS); + } + }) + .catch(function (error) { + // TODO: Add retries + console.log('[smartui] Cannot fetch latest build of the project. Error: ', error.message); + process.exit(constants.ERROR_CATCHALL); + }); +} + +function validateConfig(configFile) { + // Verify config file exists + if (!fs.existsSync(configFile)) { + console.log(`[smartui] Error: Config file ${configFile} not found.`); + process.exit(constants.ERROR_CATCHALL); + } + + // Parse JSON + let storybookConfig; + try { + storybookConfig = JSON.parse(fs.readFileSync(configFile)).storybook; + } catch (error) { + console.log('[smartui] Error: ', error.message); + process.exit(constants.ERROR_CATCHALL); + } + + try { + validateConfigBrowsers(storybookConfig.browsers); + let resolutions = storybookConfig.resolutions || storybookConfig.viewports + if (resolutions) { + storybookConfig.resolutions = validateConfigResolutions(resolutions); + } + storybookConfig.viewports = storybookConfig.resolutions; + let customViewports = storybookConfig.customViewports; + if (customViewports && customViewports.length > 0) { + validateCustomViewPorts(storybookConfig.customViewports) + } + if (!resolutions && (!customViewports || customViewports.length === 0)) { + console.log('[smartui] Error: No resolutions or customViewports found in config file'); + process.exit(constants.ERROR_CATCHALL); + } + } catch (error) { + console.log(`[smartui] Error: Invalid config, ${error.message}`); + process.exit(constants.ERROR_CATCHALL); + } + + // Sanity check waitForTimeout + if (!Object.hasOwn(storybookConfig, 'waitForTimeout')) { + storybookConfig.waitForTimeout = 0; + } else if (storybookConfig.waitForTimeout <= 0 || storybookConfig.waitForTimeout > 300000) { + console.log('[smartui] Warning: Invalid config, value of waitForTimeout must be > 0 and <= 300000'); + console.log('[smartui] If you do not wish to include waitForTimeout parameter, remove it from the config file.'); + storybookConfig.waitForTimeout = 0; + } + + return storybookConfig +} + +function validateTunnel(configFile) { + // Verify config file exists + if (!fs.existsSync(configFile)) { + console.log(`[smartui] Error: Config file ${configFile} not found.`); + process.exit(constants.ERROR_CATCHALL); + } + + let tunnelConfig; + try { + let config = JSON.parse(fs.readFileSync(configFile)); + tunnelConfig = config.tunnel || {}; + if (tunnelConfig && tunnelConfig.type && tunnelConfig.type != "manual") { + throw new ValidationError('Invalid tunnel type. Accepted type is `manual` only'); + } + } catch (error) { + console.log('[smartui] Error: ', error.message); + process.exit(constants.ERROR_CATCHALL); + } + + return tunnelConfig +} + +function validateConfigBrowsers(browsers) { + if (browsers.length == 0) { + throw new ValidationError('empty browsers list.'); + } + const set = new Set(); + for (let element of browsers) { + if (!constants.VALID_BROWSERS.includes(element.toLowerCase()) || set.has(element)) { + throw new ValidationError(`invalid or duplicate value for browser. Accepted browsers are ${constants.VALID_BROWSERS.join(',')}`); + } + set.add(element); + }; +} + +function validateConfigResolutions(resolutions) { + if (!Array.isArray(resolutions)) { + throw new ValidationError('Invalid viewports config. Please add atleast one viewport.'); + } + if (resolutions.length == 0) { + throw new ValidationError('Empty viewports list in config.'); + } + if (resolutions.length > 5) { + throw new ValidationError(`max resolutions: ${MAX_RESOLUTIONS}`); + } + let res = []; + resolutions.forEach(element => { + if (!Array.isArray(element) || element.length == 0 || element.length > 2) { + throw new ValidationError('Invalid elements in viewports config.'); + } + let width = element[0]; + let height = element[1]; + if (typeof width != 'number') { + width = Number(width); + } + if (typeof height != 'number') { + height = Number(height); + } + if (width && width < MIN_RESOLUTION_WIDTH || width > MAX_RESOLUTION_WIDTH) { + throw new ValidationError(`width must be > ${MIN_RESOLUTION_WIDTH}, < ${MAX_RESOLUTION_WIDTH}`); + } + if (height && (height < MIN_RESOLUTION_HEIGHT|| height > MAX_RESOLUTION_HEIGHT)) { + throw new ValidationError(`height must be > ${MIN_RESOLUTION_HEIGHT}, < ${MAX_RESOLUTION_HEIGHT}`); + } + res.push([width, height || 0]); + }); + + return res +} + + +function validateCustomViewPorts(customViewports) { + if (!Array.isArray(customViewports)) { + return + } + if (customViewports && customViewports.length == 0) { + return + } + customViewports.forEach(element => { + if (element.stories && element.stories.length !== 0 && element.exclude && element.exclude.length !== 0) { + throw new ValidationError('Cannot specify both stories and excludeStories in customViewports'); + } + if (element.styles) { + if (!element.styles?.width) { + throw new ValidationError('Missing width in styles. please check the config file'); + } + let width = element.styles.width; + let height = element.styles.height; + if (width && typeof width != 'number') { + width = Number(width); + } + if (height && typeof height != 'number') { + height = Number(height); + } + if (width && width < MIN_RESOLUTION_WIDTH || width > MAX_RESOLUTION_WIDTH) { + throw new ValidationError(`customViewports.styles width must be > ${MIN_RESOLUTION_WIDTH}, < ${MAX_RESOLUTION_WIDTH}`); + } + if (height && (height < MIN_RESOLUTION_HEIGHT || height > MAX_RESOLUTION_HEIGHT)) { + throw new ValidationError(`customViewports.styles height must be > ${MIN_RESOLUTION_HEIGHT}, < ${MAX_RESOLUTION_HEIGHT}`); + } + element.styles.width = width; + element.styles.height = height; + } else { + if (!element.waitForTimeout) { + throw new ValidationError('Missing styles and waitForTimeout. Specify either of them. please check the config file'); + } + } + + }); + return +} + +module.exports = { + ValidationError, + validateProjectToken, + validateStorybookUrl, + validateStorybookDir, + validateLatestBuild, + validateConfig, + validateConfigBrowsers, + validateConfigResolutions, + validateCustomViewPorts, + validateTunnel, +}; diff --git a/src/storybookVendor/index.cjs b/src/storybookVendor/index.cjs new file mode 100644 index 0000000..e200c3d --- /dev/null +++ b/src/storybookVendor/index.cjs @@ -0,0 +1,65 @@ +// Vendored, faithful relocation of @lambdatest/smartui-storybook v1.1.32. +// This preserves the PROVEN, shipping Storybook engine and its /storybook/* backend +// flow verbatim — it is only relocated into the unified smartui-cli binary so there +// is one `smartui` binary instead of two colliding ones. Behavior is unchanged. +// +// The action bodies below mirror the original package's index.js command actions +// (minus the standalone version banner / update check, which the host CLI owns). +// +// NOTE: modules are required lazily inside the functions and accessed via the module +// object (not top-level destructuring) so the bundled graph is fully initialized +// before any binding is read — this avoids esbuild capturing an export too early. + +// Mirrors index.js `storybook` action. +async function runStorybook(serve, options) { + const { storybook } = require('./commands/storybook.cjs'); + const validate = require('./commands/utils/validate.cjs'); + + options.env = options.env || 'prod'; + + // Reject an explicitly-empty --buildName, exactly as the original did. + if (options.buildName === '') { + const error = { + error: 'MISSING_BUILD_NAME', + message: 'The --buildName flag requires a value.', + }; + console.log(JSON.stringify(error, null, 2)); + process.exit(1); + } + + if (options.config) { + options.tunnel = validate.validateTunnel(options.config); + options.config = validate.validateConfig(options.config); + } + + await validate.validateProjectToken(options); + + // Validate the target before the duplicate-build check, not after. The duplicate check + // short-circuits the run with "Build with commit ... already exists", so when it ran + // first a missing directory or an unreachable Storybook URL was reported as a duplicate + // build. The target checks are read-only and idempotent, so storybook() re-running them + // costs nothing beyond one extra HEAD-shaped request in URL mode. + if (/^https?:\/\//.test(serve)) { + await validate.validateStorybookUrl(serve); + } else { + await validate.validateStorybookDir(serve); + } + + if (!options.forceRebuild) await validate.validateLatestBuild(options); + await storybook(serve, options); +} + +// Mirrors index.js `config create` action. +function createStorybookConfig(filepath) { + const { createConfig } = require('./commands/config.cjs'); + createConfig(filepath); +} + +// Exported so the command wrapper can scrub every line the engine prints, not just the +// messages the engine itself remembers to scrub. +function redactSecrets(value) { + const { redact } = require('./commands/utils/redact.cjs'); + return redact(value); +} + +module.exports = { runStorybook, createStorybookConfig, redactSecrets }; diff --git a/src/storybookVendor/index.d.cts b/src/storybookVendor/index.d.cts new file mode 100644 index 0000000..2d8ba48 --- /dev/null +++ b/src/storybookVendor/index.d.cts @@ -0,0 +1,49 @@ +// Type surface for the vendored Storybook engine. +// +// The engine itself stays untouched JavaScript on purpose: it is a faithful +// relocation of the shipping @lambdatest/smartui-storybook package, and +// rewriting it in TypeScript would defeat the point of vendoring something +// already proven in production. Declaring its public surface here is what lets +// src/commander/storybook.ts drop its `@ts-nocheck`. + +/** Options accepted by the `smartui storybook` command action. */ +export interface StorybookRunOptions { + /** Path to a SmartUI config file carrying a `storybook` block. */ + config?: string; + /** Skip the duplicate-build check and re-run against an existing build. */ + forceRebuild?: boolean; + /** Build name to report to the dashboard. */ + buildName?: string; + /** Runtime environment. Defaults to 'prod' when unset. */ + env?: 'prod' | 'stage'; + /** Populated by the engine from the config file when a tunnel is configured. */ + tunnel?: unknown; + /** Any additional flags merged in from the root command's global options. */ + [key: string]: unknown; +} + +/** + * Snapshot a Storybook, either a live server URL or a static build directory. + * Resolves once the build has been created and submitted. + */ +export declare function runStorybook( + serve: string, + options: StorybookRunOptions, +): Promise; + +/** Write a starter config containing a `storybook` block to `filepath`. */ +export declare function createStorybookConfig(filepath: string): void; + +/** + * Replace credentials in a string with [REDACTED]. Non-strings are returned unchanged. + * The backend echoes the caller's access key in at least one error message, so anything + * derived from a server response is scrubbed before being printed. + */ +export declare function redactSecrets(value: T): T; + +declare const _default: { + runStorybook: typeof runStorybook; + createStorybookConfig: typeof createStorybookConfig; + redactSecrets: typeof redactSecrets; +}; +export default _default; diff --git a/src/types.ts b/src/types.ts index 426b0c9..b117df8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,13 +48,22 @@ export interface Context { rejectionThreshold?: number; showRenderErrors?: boolean; customCSS?: string; + storybook?: StorybookConfig; }; uploadFilePath: string; webStaticConfig: WebStaticConfig; build: Build; git: Git; + storybook?: { + mode?: 'url' | 'dir'; + // URL mode: map of storyId -> { name, kind, url(iframe) } + stories?: Record; + // DIR mode: enumerated storyIds to render server-side + storyIds?: Array; + }; args: { - execCommand?: Array + execCommand?: Array; + storybookTarget?: string; } tunnelDetails: { tunnelPort: number; @@ -306,6 +315,35 @@ export interface tunnelConfig { environment:string; } +export interface StorybookStory { + name: string; + kind?: string; + url: string; +} + +export interface StorybookCustomViewport { + stories?: Array; + exclude?: Array; + styles?: { width: number, height?: number }; + waitForTimeout?: number; +} + +export interface StorybookConfig { + browsers?: Array; + // [ [w] | [w,h] ] pairs; resolutions takes precedence over viewports + viewports?: Array<[number] | [number, number]>; + resolutions?: Array<[number] | [number, number]>; + waitForTimeout?: number; + include?: Array; + exclude?: Array; + customViewports?: Array; + useOnlyCustomViewports?: boolean; + backgroundTheme?: 'light' | 'dark' | 'both'; + useGlobals?: boolean; + lazyLoadedStories?: Array; + chunkSize?: number; +} + export interface FigmaWebConfig { autoDetectViewports: Array; configs: Array<{ figma_file_token: string, figma_ids: Array, screenshot_names:Array }>; diff --git a/test/redact.test.ts b/test/redact.test.ts new file mode 100644 index 0000000..1778b71 --- /dev/null +++ b/test/redact.test.ts @@ -0,0 +1,56 @@ +// The backend echoes the caller's access key in a failed /token/verify response, so anything +// derived from a server message is scrubbed before it reaches stdout or a CI log. +import { describe, it, expect, afterEach } from 'vitest'; +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); +const { redact } = require('../src/storybookVendor/commands/utils/redact.cjs'); + +const ORIGINAL_ENV = { ...process.env }; +afterEach(() => { process.env = { ...ORIGINAL_ENV }; }); + +describe('redact', () => { + it('scrubs an access key echoed back by the auth endpoint', () => { + const msg = 'Authentication failed for provided username: bob and accessKey: LT_abcdefghijklmnopqrstuvwxyz0123456789'; + const out = redact(msg); + expect(out).not.toMatch(/LT_abcdef/); + expect(out).toContain('[REDACTED]'); + expect(out).toContain('username: bob'); + }); + + it('scrubs a composite project token', () => { + const out = redact('Failed POST for projectToken: 3128042#01M1KCEV5GKHEPGHWGR6HVCVV7#My-Project due to x'); + expect(out).not.toMatch(/01M1KCEV5GKHEPGHWGR6HVCVV7/); + expect(out).toContain('[REDACTED]'); + }); + + it('scrubs the exact env values even when they do not match the generic shapes', () => { + process.env.LT_ACCESS_KEY = 'some-unusual-key-value'; + process.env.PROJECT_TOKEN = 'another-odd-token'; + const out = redact('key=some-unusual-key-value token=another-odd-token'); + expect(out).toBe('key=[REDACTED] token=[REDACTED]'); + }); + + it('ignores short or empty env values rather than redacting everything', () => { + process.env.LT_ACCESS_KEY = 'ab'; + expect(redact('a stable message about ab')).toBe('a stable message about ab'); + }); + + it('leaves messages without secrets untouched', () => { + const msg = 'Given directory is not a storybook static directory. Error: No index.html found'; + expect(redact(msg)).toBe(msg); + }); + + it('passes non-strings through unchanged', () => { + expect(redact(42)).toBe(42); + expect(redact(null)).toBe(null); + expect(redact(undefined)).toBe(undefined); + const obj = { a: 1 }; + expect(redact(obj)).toBe(obj); + }); + + it('scrubs every occurrence, not just the first', () => { + const out = redact('LT_aaaaaaaaaaaaaaaaaaaaaa and LT_bbbbbbbbbbbbbbbbbbbbbb'); + expect(out).toBe('[REDACTED] and [REDACTED]'); + }); +}); diff --git a/test/storybook-config-generator.test.ts b/test/storybook-config-generator.test.ts new file mode 100644 index 0000000..a25d94e --- /dev/null +++ b/test/storybook-config-generator.test.ts @@ -0,0 +1,158 @@ +// TE-23033: `config:create` and `config:create-storybook` both default to .smartui.json. +// The schema lets one file carry both a `web` and a `storybook` block, so the generator +// adds the block to an existing file instead of refusing to write. +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { createStorybookConfig, createConfig } from '../src/lib/config.js'; + +let dir: string; +let logs: string[]; + +beforeEach(() => { + dir = fs.mkdtempSync(path.join(os.tmpdir(), 'smartui-config-')); + logs = []; + vi.spyOn(console, 'log').mockImplementation((...a: unknown[]) => { logs.push(a.map(String).join(' ')); }); +}); + +afterEach(() => { + vi.restoreAllMocks(); + fs.rmSync(dir, { recursive: true, force: true }); +}); + +const read = (p: string) => JSON.parse(fs.readFileSync(p, 'utf8')); + +describe('createStorybookConfig', () => { + it('creates a new config carrying a storybook block', () => { + const p = path.join(dir, '.smartui.json'); + createStorybookConfig(p); + expect(fs.existsSync(p)).toBe(true); + expect(read(p)).toHaveProperty('storybook'); + }); + + it('adds a storybook block to an existing web config instead of refusing (TE-23033)', () => { + const p = path.join(dir, '.smartui.json'); + createConfig(p); + const before = read(p); + expect(before).toHaveProperty('web'); + expect(before).not.toHaveProperty('storybook'); + + createStorybookConfig(p); + + const after = read(p); + expect(after).toHaveProperty('storybook'); + // the pre-existing web block must survive untouched + expect(after.web).toEqual(before.web); + expect(logs.join('\n')).toMatch(/Added SmartUI Storybook config to existing config/); + }); + + it('refuses when the file already has a storybook block, and says how to make a second file', () => { + const p = path.join(dir, '.smartui.json'); + createStorybookConfig(p); + const before = read(p); + + createStorybookConfig(p); + + expect(read(p)).toEqual(before); + expect(logs.join('\n')).toMatch(/already exists/); + expect(logs.join('\n')).toMatch(/config:create-storybook \.smartui-storybook\.json/); + }); + + it('rejects a non-json extension without writing anything', () => { + const p = path.join(dir, 'config.yaml'); + createStorybookConfig(p); + expect(fs.existsSync(p)).toBe(false); + expect(logs.join('\n')).toMatch(/must have \.json extension/); + }); + + it('reports a malformed existing config rather than overwriting it', () => { + const p = path.join(dir, '.smartui.json'); + fs.writeFileSync(p, '{ not valid json'); + createStorybookConfig(p); + expect(fs.readFileSync(p, 'utf8')).toBe('{ not valid json'); + expect(logs.join('\n')).toMatch(/Cannot read existing config/); + }); +}); + +describe('createConfig, the reverse direction of TE-23033', () => { + it('adds a web block to a config that only has a storybook block', () => { + // The two generators share the .smartui.json default path, so running them in the + // other order has to work too, not just storybook-after-web. + const p = path.join(dir, '.smartui.json'); + createStorybookConfig(p); + const before = read(p); + expect(before).not.toHaveProperty('web'); + + createConfig(p); + + const after = read(p); + expect(after).toHaveProperty('web'); + expect(after.storybook).toEqual(before.storybook); + expect(logs.join('\n')).toMatch(/Added SmartUI Config to existing config/); + }); + + it('produces the same file whichever order the two generators run in', () => { + const a = path.join(dir, 'a.json'); + const b = path.join(dir, 'b.json'); + createConfig(a); createStorybookConfig(a); + createStorybookConfig(b); createConfig(b); + const [ra, rb] = [read(a), read(b)]; + expect(new Set(Object.keys(ra))).toEqual(new Set(Object.keys(rb))); + expect(ra.web).toEqual(rb.web); + expect(ra.storybook).toEqual(rb.storybook); + }); + + it('still refuses when a web block is already present', () => { + const p = path.join(dir, '.smartui.json'); + createConfig(p); + const before = read(p); + createConfig(p); + expect(read(p)).toEqual(before); + expect(logs.join('\n')).toMatch(/SmartUI Config already exists/); + }); +}); + +describe('existing files that are not usable config objects', () => { + // All of these previously went wrong: a BOM made the file unreadable, an array reported + // success while JSON.stringify silently dropped the added property, and `null` crashed with + // an unhandled TypeError and a Node stack trace. + const write = (name: string, content: string) => { + const p = path.join(dir, name); + fs.writeFileSync(p, content); + return p; + }; + + it('merges into a file that starts with a BOM', () => { + const p = write('bom.json', '\uFEFF{"web":{"browsers":["chrome"]}}'); + createStorybookConfig(p); + const after = JSON.parse(fs.readFileSync(p, 'utf8').replace(/^\uFEFF/, '')); + expect(Object.keys(after)).toEqual(['web', 'storybook']); + }); + + it.each([ + ['an array', '[1,2,3]', /found an array/], + ['null', 'null', /found null/], + ['a string', '"hello"', /found string/], + ['a number', '42', /found number/], + ])('refuses %s without modifying the file', (_label, content, matcher) => { + const p = write('x.json', content); + createStorybookConfig(p); + expect(fs.readFileSync(p, 'utf8')).toBe(content); + expect(logs.join('\n')).toMatch(matcher); + }); + + it('createConfig refuses the same shapes', () => { + const p = write('y.json', '[1,2]'); + createConfig(p); + expect(fs.readFileSync(p, 'utf8')).toBe('[1,2]'); + expect(logs.join('\n')).toMatch(/found an array/); + }); + + it('reports an unreadable file rather than throwing', () => { + createStorybookConfig(path.join(dir, 'no-such-dir', 'deep', 'a.json')); + // A path whose parent does not exist is a create, not a merge, so it must succeed. + expect(fs.existsSync(path.join(dir, 'no-such-dir', 'deep', 'a.json'))).toBe(true); + }); +}); + diff --git a/test/storybook-config-schema.test.ts b/test/storybook-config-schema.test.ts new file mode 100644 index 0000000..a5b7905 --- /dev/null +++ b/test/storybook-config-schema.test.ts @@ -0,0 +1,180 @@ +// Covers the `storybook` block added to ConfigSchema, and the SnapshotSchema regression +// QA hit as an HTTP 500 "Invalid snapshot" (TE-24908). That one was a stale branch base +// rather than a product defect, so these cases exist to stop it silently coming back. +import { describe, it, expect } from 'vitest'; +import { validateConfig, validateSnapshot } from '../src/lib/schemaValidation.js'; + +const withStorybook = (storybook: unknown) => ({ storybook }); +const ok = (config: unknown) => validateConfig(config) === true; +const errors = (config: unknown) => { + validateConfig(config); + return (validateConfig.errors ?? []).map((e) => e.message).join(' | '); +}; + +describe('ConfigSchema: storybook block', () => { + it('accepts a config carrying only a storybook block', () => { + // The top level is additionalProperties:false with an anyOf, so `storybook` has to + // be listed in both places or a storybook-only config is rejected outright. + expect(ok(withStorybook({ browsers: ['chrome'] }))).toBe(true); + }); + + it('accepts one file carrying both a web and a storybook block', () => { + // This is what makes the TE-23033 merge legal. + expect(ok({ + web: { browsers: ['chrome'], viewports: [[1920, 1080]] }, + storybook: { browsers: ['chrome'], viewports: [[1920, 1080]] }, + })).toBe(true); + }); + + it('rejects a config with neither web, mobile nor storybook', () => { + expect(ok({})).toBe(false); + }); + + it('rejects an unknown top-level key', () => { + expect(ok({ storybook: { browsers: ['chrome'] }, storyboook: {} })).toBe(false); + }); + + it('rejects an unknown key inside the storybook block', () => { + expect(ok(withStorybook({ browsers: ['chrome'], nope: 1 }))).toBe(false); + }); + + describe('browsers', () => { + it('accepts the four supported browsers', () => { + expect(ok(withStorybook({ browsers: ['chrome', 'firefox', 'safari', 'edge'] }))).toBe(true); + }); + it('rejects an unsupported browser and names the allowed set', () => { + expect(ok(withStorybook({ browsers: ['opera'] }))).toBe(false); + expect(errors(withStorybook({ browsers: ['opera'] }))).toMatch(/allowed storybook browsers/); + }); + it('rejects an empty browsers array', () => { + expect(ok(withStorybook({ browsers: [] }))).toBe(false); + }); + it('rejects duplicate browsers', () => { + expect(ok(withStorybook({ browsers: ['chrome', 'chrome'] }))).toBe(false); + }); + }); + + describe('viewports and resolutions', () => { + it('accepts a [width] tuple', () => { + expect(ok(withStorybook({ viewports: [[1280]] }))).toBe(true); + }); + it('accepts a [width, height] tuple', () => { + expect(ok(withStorybook({ viewports: [[1280, 720]] }))).toBe(true); + }); + it('rejects a three-element tuple', () => { + expect(ok(withStorybook({ viewports: [[1280, 720, 2]] }))).toBe(false); + }); + it('rejects a width below 320', () => { + expect(ok(withStorybook({ viewports: [[319]] }))).toBe(false); + }); + it('rejects a width above 7680', () => { + expect(ok(withStorybook({ viewports: [[7681]] }))).toBe(false); + }); + it('rejects a height below 320', () => { + expect(ok(withStorybook({ viewports: [[1280, 319]] }))).toBe(false); + }); + it('rejects a non-integer dimension', () => { + expect(ok(withStorybook({ viewports: [[1280.5]] }))).toBe(false); + }); + it('caps viewports at 5', () => { + const six = Array.from({ length: 6 }, (_, i) => [1000 + i]); + expect(ok(withStorybook({ viewports: six }))).toBe(false); + expect(errors(withStorybook({ viewports: six }))).toMatch(/max storybook viewports allowed - 5/); + }); + it('caps resolutions at 5 with its own message', () => { + const six = Array.from({ length: 6 }, (_, i) => [1000 + i]); + expect(errors(withStorybook({ resolutions: six }))).toMatch(/max storybook resolutions allowed - 5/); + }); + it('rejects an empty viewports array', () => { + expect(ok(withStorybook({ viewports: [] }))).toBe(false); + }); + }); + + describe('waitForTimeout', () => { + it('accepts 0 and the 300000 ceiling', () => { + expect(ok(withStorybook({ waitForTimeout: 0 }))).toBe(true); + expect(ok(withStorybook({ waitForTimeout: 300000 }))).toBe(true); + }); + it('rejects a negative value', () => { + expect(ok(withStorybook({ waitForTimeout: -1 }))).toBe(false); + }); + it('rejects a value above the ceiling', () => { + expect(ok(withStorybook({ waitForTimeout: 300001 }))).toBe(false); + }); + }); + + describe('backgroundTheme', () => { + it.each(['light', 'dark', 'both'])('accepts %s', (theme) => { + expect(ok(withStorybook({ backgroundTheme: theme }))).toBe(true); + }); + it('rejects anything else', () => { + expect(ok(withStorybook({ backgroundTheme: 'sepia' }))).toBe(false); + }); + }); + + describe('chunkSize', () => { + it('accepts 1', () => { + expect(ok(withStorybook({ chunkSize: 1 }))).toBe(true); + }); + it('rejects 0', () => { + expect(ok(withStorybook({ chunkSize: 0 }))).toBe(false); + }); + }); + + describe('customViewports', () => { + it('accepts styles alone', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'], styles: { width: 800 } }] }))).toBe(true); + }); + it('accepts waitForTimeout alone', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'], waitForTimeout: 10 }] }))).toBe(true); + }); + it('rejects both styles and waitForTimeout together', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'], styles: { width: 800 }, waitForTimeout: 10 }] }))).toBe(false); + }); + it('rejects neither styles nor waitForTimeout', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'] }] }))).toBe(false); + }); + it('rejects stories and exclude together', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'], exclude: ['b'], styles: { width: 800 } }] }))).toBe(false); + }); + it('requires a width when styles is given', () => { + expect(ok(withStorybook({ customViewports: [{ stories: ['a'], styles: { height: 600 } }] }))).toBe(false); + }); + }); +}); + +describe('SnapshotSchema: ignoreColors (TE-24908 regression guard)', () => { + const snapshot = (options: unknown) => ({ + name: 'home', + url: 'https://example.com', + dom: { html: '' }, + options, + }); + + // Snapshot `options` is additionalProperties:false, so a branch cut before the + // ignoreColors work rejected the whole payload with the literal message + // "Invalid snapshot", surfacing as an HTTP 500 and an Error-Build with 0 screenshots. + it.each([ + ['cssSelector', { cssSelector: ['.price'] }], + ['id', { id: ['total'] }], + ['class', { class: ['muted'] }], + ['xpath', { xpath: ['//div'] }], + ['entireScreenshot', { entireScreenshot: true }], + ])('accepts ignoreColors with %s', (_label, ignoreColors) => { + validateSnapshot(snapshot({ ignoreColors })); + const messages = (validateSnapshot.errors ?? []).map((e) => e.message).join(' | '); + expect(messages).not.toMatch(/ignoreColors/); + }); + + it('still accepts ignoreDOM and selectDOM, which predate the branch cut', () => { + for (const options of [{ ignoreDOM: { cssSelector: ['.x'] } }, { selectDOM: { cssSelector: ['.x'] } }]) { + validateSnapshot(snapshot(options)); + const messages = (validateSnapshot.errors ?? []).map((e) => e.message).join(' | '); + expect(messages).not.toMatch(/ignoreDOM|selectDOM/); + } + }); + + it('rejects an unknown snapshot option', () => { + expect(validateSnapshot(snapshot({ ignoreColours: { cssSelector: ['.x'] } }))).toBe(false); + }); +}); diff --git a/test/storybook-robustness.test.ts b/test/storybook-robustness.test.ts new file mode 100644 index 0000000..bf0022b --- /dev/null +++ b/test/storybook-robustness.test.ts @@ -0,0 +1,158 @@ +// Adversarial cases: malformed story indexes and Storybook URLs that are not at the origin root. +// Everything here failed before the fixes it guards: raw TypeErrors on a truncated index, a +// string index silently yielding stories named "0".."3", and sub-path deployments resolving +// every URL against the wrong base. +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); +const { normalizeStoryEntries, skipStory } = require('../src/storybookVendor/commands/utils/story.cjs'); +const { filterStories } = require('../src/storybookVendor/commands/utils/static.cjs'); +const { storybookBase, fetchStoryIndex } = require('../src/storybookVendor/commands/storybook.cjs'); +const { httpClient } = require('../src/storybookVendor/commands/utils/httpClient.cjs'); + +describe('storybookBase', () => { + // `new URL('index.json', 'http://h/sb')` resolves to 'http://h/index.json': without a + // trailing slash the last segment is a filename and gets replaced. + it('adds a trailing slash so relative paths resolve under the base', () => { + expect(new URL('index.json', storybookBase('http://h/sb')).href).toBe('http://h/sb/index.json'); + expect(new URL('index.json', storybookBase('http://h/sb/')).href).toBe('http://h/sb/index.json'); + }); + + it('leaves an origin-root URL alone', () => { + expect(new URL('index.json', storybookBase('http://h')).href).toBe('http://h/index.json'); + expect(new URL('index.json', storybookBase('http://h/')).href).toBe('http://h/index.json'); + }); + + it('keeps story URLs under a sub-path instead of at the origin root', () => { + const base = storybookBase('http://h/team/storybook'); + expect(new URL('iframe.html?id=btn--x&viewMode=story', base).href) + .toBe('http://h/team/storybook/iframe.html?id=btn--x&viewMode=story'); + }); + + it('preserves port and deep paths', () => { + expect(new URL('index.json', storybookBase('http://h:6006/a/b/c')).href) + .toBe('http://h:6006/a/b/c/index.json'); + }); +}); + +describe('fetchStoryIndex against a sub-path', () => { + afterEach(() => vi.restoreAllMocks()); + + it('requests the index under the sub-path, not at the root', async () => { + const seen: string[] = []; + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + seen.push(url); + if (url === 'http://h/team/sb/index.json') { + return { data: { v: 5, entries: { 'a--b': { type: 'story', name: 'B' } } } }; + } + throw new Error('404'); + }); + const index = await fetchStoryIndex('http://h/team/sb'); + expect(index.source).toBe('index.json'); + expect(seen[0]).toBe('http://h/team/sb/index.json'); + }); + + it('rejects a non-index payload rather than iterating it by character', async () => { + // A proxy error page served as JSON at index.json used to yield stories "0".."3". + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + if (url.endsWith('index.json')) return { data: { entries: 'nope' } }; + throw new Error('404'); + }); + await expect(fetchStoryIndex('http://h/')).rejects.toThrow(); + }); +}); + +describe('normalizeStoryEntries', () => { + it.each([ + ['null', null], + ['undefined', undefined], + ['a string', 'nope'], + ['a number', 7], + ['an array', [{ type: 'story' }]], + ])('rejects %s', (_label, input) => { + expect(normalizeStoryEntries(input)).toBeNull(); + }); + + it('keeps object entries and drops junk ones', () => { + const out = normalizeStoryEntries({ + good: { type: 'story', name: 'Good' }, + nullish: null, + str: 'x', + arr: [1, 2], + }); + expect(Object.keys(out)).toEqual(['good']); + }); + + it('returns an empty object for an empty index rather than null', () => { + expect(normalizeStoryEntries({})).toEqual({}); + }); +}); + +describe('skipStory is null-safe', () => { + it.each([[null], [undefined], ['a string'], [42]])('skips %s instead of throwing', (input) => { + expect(skipStory(input, {})).toBe(true); + }); +}); + +describe('filterStories on malformed indexes', () => { + let dir: string; + let logs: string[]; + let exitCode: number | undefined; + let realExit: typeof process.exit; + + beforeEach(() => { + dir = fs.mkdtempSync(path.join(os.tmpdir(), 'smartui-fuzz-')); + logs = []; + exitCode = undefined; + vi.spyOn(console, 'log').mockImplementation((...a: unknown[]) => { logs.push(a.map(String).join(' ')); }); + realExit = process.exit; + // @ts-expect-error deliberately replacing process.exit for the duration of the test + process.exit = (code?: number) => { exitCode = code; throw new Error('__EXIT__'); }; + }); + afterEach(() => { + process.exit = realExit; + vi.restoreAllMocks(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + const write = (content: string) => fs.writeFileSync(path.join(dir, 'index.json'), content); + const run = () => { + try { return { ids: filterStories(dir, {}) }; } + catch (e) { return { exited: exitCode, log: logs.join('\n') }; } + }; + + it('reports a truncated index instead of throwing a SyntaxError', () => { + write('{"entries": {"a":'); + const r = run(); + expect(r.exited).toBe(1); + expect(r.log).toMatch(/Could not parse/); + }); + + it.each([ + ['entries: null', '{"v":5,"entries":null}'], + ['no entries key', '{"v":5}'], + ['entries as a string', '{"v":5,"entries":"nope"}'], + ['entries as an array', '{"v":5,"entries":[]}'], + ])('reports %s instead of throwing a TypeError', (_label, content) => { + write(content); + const r = run(); + expect(r.exited).toBe(1); + expect(r.log).toMatch(/does not contain a story index/); + }); + + it('reports an empty index through the No stories found path', () => { + write('{"v":5,"entries":{}}'); + const r = run(); + expect(r.exited).toBe(1); + expect(r.log).toMatch(/No stories found/); + }); + + it('drops junk entries but keeps the real ones', () => { + write(JSON.stringify({ v: 5, entries: { bad: null, worse: 'x', good: { type: 'story', name: 'G' } } })); + expect(run().ids).toEqual(['good']); + }); +}); diff --git a/test/storybook-story-discovery.test.ts b/test/storybook-story-discovery.test.ts new file mode 100644 index 0000000..5cb1a36 --- /dev/null +++ b/test/storybook-story-discovery.test.ts @@ -0,0 +1,156 @@ +// TE-24909: Storybook >= 8 dropped stories.json and serves index.json. URL-mode discovery +// read only the legacy file, 404'd, and the run ended with 0 screenshots. These tests pin +// both generations, both payload shapes, and the docs-entry filtering that decides which +// entries actually become screenshots. +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); + +const { httpClient } = require('../src/storybookVendor/commands/utils/httpClient.cjs'); +const { fetchStoryIndex } = require('../src/storybookVendor/commands/storybook.cjs'); +const { skipStory } = require('../src/storybookVendor/commands/utils/story.cjs'); +const { filterStories } = require('../src/storybookVendor/commands/utils/static.cjs'); + +// A Storybook 8 index.json: entries keyed by story id, docs entries carry type 'docs'. +const SB8 = { + v: 5, + entries: { + 'button--primary': { id: 'button--primary', title: 'Button', name: 'Primary', type: 'story' }, + 'button--secondary': { id: 'button--secondary', title: 'Button', name: 'Secondary', type: 'story' }, + 'button--docs': { id: 'button--docs', title: 'Button', name: 'Docs', type: 'docs' }, + }, +}; + +// A Storybook 6/7 stories.json: `stories` rather than `entries`, `kind` rather than `title`, +// docs flagged through parameters.docsOnly. +const SB7 = { + v: 4, + stories: { + 'card--default': { id: 'card--default', kind: 'Card', name: 'Default' }, + 'card--empty': { id: 'card--empty', kind: 'Card', name: 'Empty' }, + 'card--page': { id: 'card--page', kind: 'Card', name: 'Page', parameters: { docsOnly: true } }, + }, +}; + +describe('fetchStoryIndex (URL mode)', () => { + afterEach(() => vi.restoreAllMocks()); + + it('reads index.json on Storybook >= 8', async () => { + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + if (url.endsWith('/index.json')) return { data: SB8 }; + throw new Error('404'); + }); + const index = await fetchStoryIndex('http://localhost:6006/'); + expect(index.source).toBe('index.json'); + expect(Object.keys(index.entries)).toHaveLength(3); + }); + + it('falls back to stories.json when index.json is absent (legacy Storybook)', async () => { + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + if (url.endsWith('/stories.json')) return { data: SB7 }; + throw Object.assign(new Error('Request failed with status code 404'), { response: { status: 404 } }); + }); + const index = await fetchStoryIndex('http://localhost:6006/'); + expect(index.source).toBe('stories.json'); + expect(Object.keys(index.entries)).toHaveLength(3); + }); + + it('falls through when index.json exists but is empty, rather than stopping there', async () => { + // Some setups serve an index.json with no entries. Before the fix this looked like + // success and produced a zero-story run. + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + if (url.endsWith('/index.json')) return { data: { v: 5, entries: {} } }; + if (url.endsWith('/stories.json')) return { data: SB7 }; + throw new Error('404'); + }); + const index = await fetchStoryIndex('http://localhost:6006/'); + expect(index.source).toBe('stories.json'); + }); + + it('throws when neither file can be read', async () => { + vi.spyOn(httpClient, 'get').mockRejectedValue(new Error('connect ECONNREFUSED')); + await expect(fetchStoryIndex('http://localhost:6006/')).rejects.toThrow(); + }); + + it('resolves the index against a URL carrying a sub-path', async () => { + const seen: string[] = []; + vi.spyOn(httpClient, 'get').mockImplementation(async (url: string) => { + seen.push(url); + if (url.endsWith('/index.json')) return { data: SB8 }; + throw new Error('404'); + }); + await fetchStoryIndex('http://localhost:6006/storybook/'); + expect(seen[0]).toBe('http://localhost:6006/storybook/index.json'); + }); +}); + +describe('skipStory', () => { + it('skips Storybook 8 docs entries', () => { + expect(skipStory({ type: 'docs', name: 'Docs' }, {})).toBe(true); + }); + + it('skips Storybook 7 docsOnly entries', () => { + expect(skipStory({ parameters: { docsOnly: true }, name: 'Page' }, {})).toBe(true); + }); + + it('keeps a plain story', () => { + expect(skipStory({ type: 'story', name: 'Primary' }, {})).toBe(false); + }); + + it('honours include as a regex string', () => { + const config = { include: ['/^Prim/'] }; + expect(skipStory({ name: 'Primary' }, config)).toBe(false); + expect(skipStory({ name: 'Secondary' }, config)).toBe(true); + }); + + it('honours exclude as a regex string', () => { + const config = { exclude: ['/Secondary/'] }; + expect(skipStory({ name: 'Primary' }, config)).toBe(false); + expect(skipStory({ name: 'Secondary' }, config)).toBe(true); + }); +}); + +describe('filterStories (DIR mode)', () => { + let dir: string; + beforeEach(() => { + dir = fs.mkdtempSync(path.join(os.tmpdir(), 'smartui-static-')); + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + afterEach(() => { + vi.restoreAllMocks(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + it('reads index.json entries and drops docs (Storybook >= 8 static build)', () => { + fs.writeFileSync(path.join(dir, 'index.json'), JSON.stringify(SB8)); + expect(filterStories(dir, {})).toEqual(['button--primary', 'button--secondary']); + }); + + it('reads legacy stories.json and drops docsOnly', () => { + fs.writeFileSync(path.join(dir, 'stories.json'), JSON.stringify(SB7)); + expect(filterStories(dir, {})).toEqual(['card--default', 'card--empty']); + }); + + it('prefers index.json when both files are present, matching URL mode', () => { + // A static dir rebuilt from Storybook 7 to 8 can keep a stale stories.json next to + // the new index.json. Reading the stale one would give DIR mode a different story + // set from URL mode against the same Storybook. + fs.writeFileSync(path.join(dir, 'index.json'), JSON.stringify(SB8)); + fs.writeFileSync(path.join(dir, 'stories.json'), JSON.stringify(SB7)); + expect(filterStories(dir, {})).toEqual(['button--primary', 'button--secondary']); + }); + + it('reads a legacy file that uses entries rather than stories', () => { + fs.writeFileSync(path.join(dir, 'stories.json'), JSON.stringify({ v: 4, entries: SB7.stories })); + expect(filterStories(dir, {})).toEqual(['card--default', 'card--empty']); + }); + + it('applies the include filter', () => { + fs.writeFileSync(path.join(dir, 'index.json'), JSON.stringify(SB8)); + expect(filterStories(dir, { include: ['/^Primary$/'] })).toEqual(['button--primary']); + }); +}); diff --git a/tsconfig.storybook.json b/tsconfig.storybook.json new file mode 100644 index 0000000..2ddef49 --- /dev/null +++ b/tsconfig.storybook.json @@ -0,0 +1,22 @@ +{ + // Scoped typecheck for the Storybook unification surface. + // + // The repository as a whole does not typecheck today: tsup/esbuild strips types + // without checking them, and `tsc --noEmit` reports 251 pre-existing errors across + // files this branch never touches. Fixing those is not this change's job, but the + // code this branch adds should still be checked, which is what lets + // src/commander/storybook.ts drop its `@ts-nocheck`. + // + // Run with: pnpm run typecheck:storybook + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "NodeNext", + "noEmit": true, + "allowJs": false + }, + "files": [ + "src/commander/storybook.ts", + "src/storybookVendor/index.d.cts", + "src/lib/tui.d.cts" + ] +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..fa69665 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['test/**/*.test.ts'], + environment: 'node', + }, +});