diff --git a/package-lock.json b/package-lock.json index 0c4d97edad..02589788c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1861,7 +1861,7 @@ "version": "18.19.68", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz", "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -2191,129 +2191,6 @@ "vue": "^3.2.25" } }, - "node_modules/@vue/compiler-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.13", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT", - "peer": true - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.13", - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.11", - "postcss": "^8.4.48", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT", - "peer": true - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/reactivity": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", - "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", - "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/reactivity": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", - "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/reactivity": "3.5.13", - "@vue/runtime-core": "3.5.13", - "@vue/shared": "3.5.13", - "csstype": "^3.1.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", - "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13" - }, - "peerDependencies": { - "vue": "3.5.13" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", - "license": "MIT", - "peer": true - }, "node_modules/@zip.js/zip.js": { "version": "2.7.32", "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.32.tgz", @@ -2335,6 +2212,7 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -2432,6 +2310,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, "dependencies": { "dequal": "^2.0.3" } @@ -2609,16 +2488,30 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dev": true, "dependencies": { "dequal": "^2.0.3" } }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bare-events": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.2.tgz", + "integrity": "sha512-KSdMqLj1ZERZMP1PTmnLK7SqJu9z9/SbwUUPZly2puMtfVcytC+jl6mb/9XYiqq0PXcx1rNDS+Qvl1g54Lho6A==", + "license": "Apache-2.0", + "optional": true + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2862,6 +2755,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", @@ -3029,6 +2923,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -3040,7 +2935,8 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true }, "node_modules/data-view-buffer": { "version": "1.0.1", @@ -3223,6 +3119,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, "engines": { "node": ">=6" } @@ -3234,13 +3131,6 @@ "dev": true, "optional": true }, - "node_modules/devtools-protocol": { - "version": "0.0.1349977", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1349977.tgz", - "integrity": "sha512-5JcwlDKinshGSm+4AVLFCkokJUAKTgjmiorNmrGgYYKix1h8Ts9/fplQeK1xg/rACYw1JlEM2PwIEvny5QswKQ==", - "dev": true, - "peer": true - }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", @@ -3329,24 +3219,10 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -3917,6 +3793,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, "dependencies": { "@types/estree": "^1.0.0" } @@ -3956,6 +3833,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -4875,6 +4758,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dev": true, "dependencies": { "@types/estree": "*" } @@ -5198,7 +5082,8 @@ "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true }, "node_modules/locate-path": { "version": "6.0.0", @@ -5316,7 +5201,8 @@ "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true }, "node_modules/merge2": { "version": "1.4.1", @@ -5632,7 +5518,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -5785,6 +5670,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dev": true, "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", @@ -5905,10 +5791,10 @@ } }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -5958,6 +5844,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "license": "MIT" + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -6543,6 +6435,20 @@ "integrity": "sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==", "dev": true }, + "node_modules/streamx": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", + "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -6705,6 +6611,7 @@ "version": "4.2.19", "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -6736,6 +6643,15 @@ "svelte": "^3.19.0 || ^4.0.0" } }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6905,7 +6821,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -6946,7 +6862,7 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true + "dev": true }, "node_modules/universalify": { "version": "0.1.2", @@ -7464,28 +7380,6 @@ } } }, - "node_modules/vue": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", - "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-sfc": "3.5.13", - "@vue/runtime-dom": "3.5.13", - "@vue/server-renderer": "3.5.13", - "@vue/shared": "3.5.13" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/web": { "resolved": "packages/web", "link": true @@ -7604,8 +7498,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { "version": "8.17.1", @@ -7819,6 +7712,12 @@ "packages/playwright-core": { "version": "1.50.0-next", "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.7", + "fast-fifo": "^1.3.2", + "pump": "^3.0.2", + "streamx": "^2.21.1" + }, "bin": { "playwright-core": "cli.js" }, diff --git a/packages/playwright-core/bundles/zip/package-lock.json b/packages/playwright-core/bundles/zip/package-lock.json index 23c3c1ae90..8476d11c19 100644 --- a/packages/playwright-core/bundles/zip/package-lock.json +++ b/packages/playwright-core/bundles/zip/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.1", "dependencies": { "extract-zip": "2.0.1", - "tar-fs": "^3.0.6", "yauzl": "2.10.0", "yazl": "2.5.1" }, @@ -42,58 +41,6 @@ "@types/node": "*" } }, - "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", - "license": "Apache-2.0" - }, - "node_modules/bare-events": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", - "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", - "license": "Apache-2.0", - "optional": true - }, - "node_modules/bare-fs": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", - "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "bare-stream": "^2.0.0" - } - }, - "node_modules/bare-os": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", - "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", - "license": "Apache-2.0", - "optional": true - }, - "node_modules/bare-path": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", - "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-os": "^2.1.0" - } - }, - "node_modules/bare-stream": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.1.tgz", - "integrity": "sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "streamx": "^2.21.0" - } - }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -145,12 +92,6 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "license": "MIT" - }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -200,60 +141,6 @@ "once": "^1.3.1" } }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "license": "MIT" - }, - "node_modules/streamx": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", - "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/tar-fs": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", - "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -302,52 +189,6 @@ "@types/node": "*" } }, - "b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" - }, - "bare-events": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", - "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", - "optional": true - }, - "bare-fs": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", - "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", - "optional": true, - "requires": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "bare-stream": "^2.0.0" - } - }, - "bare-os": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", - "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", - "optional": true - }, - "bare-path": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", - "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", - "optional": true, - "requires": { - "bare-os": "^2.1.0" - } - }, - "bare-stream": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.1.tgz", - "integrity": "sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==", - "optional": true, - "requires": { - "streamx": "^2.21.0" - } - }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -380,11 +221,6 @@ "yauzl": "^2.10.0" } }, - "fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" - }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -428,51 +264,6 @@ "once": "^1.3.1" } }, - "queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" - }, - "streamx": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", - "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", - "requires": { - "bare-events": "^2.2.0", - "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", - "text-decoder": "^1.1.0" - } - }, - "tar-fs": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", - "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", - "requires": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0", - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - } - }, - "tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "requires": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "requires": { - "b4a": "^1.6.4" - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/packages/playwright-core/bundles/zip/package.json b/packages/playwright-core/bundles/zip/package.json index e1268b08a8..0d9650d284 100644 --- a/packages/playwright-core/bundles/zip/package.json +++ b/packages/playwright-core/bundles/zip/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "extract-zip": "2.0.1", - "tar-fs": "^3.0.6", "yauzl": "2.10.0", "yazl": "2.5.1" }, diff --git a/packages/playwright-core/bundles/zip/src/zipBundleImpl.ts b/packages/playwright-core/bundles/zip/src/zipBundleImpl.ts index 1e9fd95432..b69e1a168a 100644 --- a/packages/playwright-core/bundles/zip/src/zipBundleImpl.ts +++ b/packages/playwright-core/bundles/zip/src/zipBundleImpl.ts @@ -18,5 +18,3 @@ export * as yazl from 'yazl'; export * as yauzl from 'yauzl'; import extractZip from 'extract-zip'; export const extract = extractZip; -// @ts-expect-error @types/tar-fs is broken and we're fine without it -export * as tarFs from 'tar-fs'; diff --git a/packages/playwright-core/package.json b/packages/playwright-core/package.json index 9b484085dd..1e1ac247a7 100644 --- a/packages/playwright-core/package.json +++ b/packages/playwright-core/package.json @@ -40,5 +40,11 @@ "bin": { "playwright-core": "cli.js" }, - "types": "types/types.d.ts" + "types": "types/types.d.ts", + "dependencies": { + "b4a": "^1.6.7", + "fast-fifo": "^1.3.2", + "pump": "^3.0.2", + "streamx": "^2.21.1" + } } diff --git a/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts b/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts index d764fe2d9f..a57508e357 100644 --- a/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts +++ b/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts @@ -18,7 +18,8 @@ import fs from 'fs'; import path from 'path'; import { httpRequest } from '../../utils/network'; import { ManualPromise } from '../../utils/manualPromise'; -import { extract, tarFs } from '../../zipBundle'; +import { extract } from '../../zipBundle'; +import tar from '../../utils/tar'; import type http from 'http'; import { pipeline } from 'stream/promises'; import { createBrotliDecompress } from 'zlib'; @@ -150,7 +151,7 @@ async function downloadAndExtractBrotli(options: DownloadParams) { await pipeline( response, createBrotliDecompress(), - tarFs.extract(options.browserDirectory) + tar.extract(options.browserDirectory) ); if (downloadedBytes !== totalBytes) diff --git a/packages/playwright-core/src/utils/tar/README.md b/packages/playwright-core/src/utils/tar/README.md new file mode 100644 index 0000000000..e6d4622c8a --- /dev/null +++ b/packages/playwright-core/src/utils/tar/README.md @@ -0,0 +1 @@ +This directory contains a modified copy of the `tar-stream` library that's used exclusively to extract TAR files. diff --git a/packages/playwright-core/src/utils/tar/extract.js b/packages/playwright-core/src/utils/tar/extract.js new file mode 100644 index 0000000000..2a19f9f612 --- /dev/null +++ b/packages/playwright-core/src/utils/tar/extract.js @@ -0,0 +1,311 @@ +const { Writable, Readable, getStreamError } = require('stream') +const headers = require('./headers') + +const EMPTY = Buffer.alloc(0) + +class BufferList { + constructor () { + this.buffered = 0 + this.shifted = 0 + this.queue = [] + + this._offset = 0 + } + + push (buffer) { + this.buffered += buffer.byteLength + this.queue.push(buffer) + } + + shiftFirst (size) { + return this._buffered === 0 ? null : this._next(size) + } + + shift (size) { + if (size > this.buffered) return null + if (size === 0) return EMPTY + + let chunk = this._next(size) + + if (size === chunk.byteLength) return chunk // likely case + + const chunks = [chunk] + + while ((size -= chunk.byteLength) > 0) { + chunk = this._next(size) + chunks.push(chunk) + } + + return Buffer.concat(chunks) + } + + _next (size) { + const buf = this.queue[0] + const rem = buf.byteLength - this._offset + + if (size >= rem) { + const sub = this._offset ? buf.subarray(this._offset, buf.byteLength) : buf + this.queue.shift() + this._offset = 0 + this.buffered -= rem + this.shifted += rem + return sub + } + + this.buffered -= size + this.shifted += size + + return buf.subarray(this._offset, (this._offset += size)) + } +} + +class Source extends Readable { + constructor (self, header, offset) { + super() + + this.header = header + this.offset = offset + + this._parent = self + } + + _read () { + if (this.header.size === 0) { + this.push(null) + } + if (this._parent._stream === this) { + this._parent._update() + } + } + + _predestroy () { + this._parent.destroy(getStreamError(this)) + } + + _detach () { + if (this._parent._stream === this) { + this._parent._stream = null + this._parent._missing = overflow(this.header.size) + this._parent._update() + } + } + + _destroy (err, cb) { + this._detach() + cb(null) + } +} + +class Extract extends Writable { + constructor (opts) { + super(opts) + + if (!opts) opts = {} + + this._buffer = new BufferList() + this._offset = 0 + this._header = null + this._stream = null + this._missing = 0 + this._longHeader = false + this._callback = noop + this._locked = false + this._finished = false + this._pax = null + this._paxGlobal = null + this._gnuLongPath = null + this._gnuLongLinkPath = null + this._filenameEncoding = opts.filenameEncoding || 'utf-8' + this._allowUnknownFormat = !!opts.allowUnknownFormat + this._unlockBound = this._unlock.bind(this) + } + + _unlock (err) { + this._locked = false + + if (err) { + this.destroy(err) + this._continueWrite(err) + return + } + + this._update() + } + + _consumeHeader () { + if (this._locked) return false + + this._offset = this._buffer.shifted + + try { + this._header = headers.decode(this._buffer.shift(512), this._filenameEncoding, this._allowUnknownFormat) + } catch (err) { + this._continueWrite(err) + return false + } + + if (!this._header) return true + + switch (this._header.type) { + case 'gnu-long-path': + case 'gnu-long-link-path': + case 'pax-global-header': + case 'pax-header': + this._longHeader = true + this._missing = this._header.size + return true + } + + this._locked = true + this._applyLongHeaders() + + if (this._header.size === 0 || this._header.type === 'directory') { + this.emit('entry', this._header, this._createStream(), this._unlockBound) + return true + } + + this._stream = this._createStream() + this._missing = this._header.size + + this.emit('entry', this._header, this._stream, this._unlockBound) + return true + } + + _applyLongHeaders () { + if (this._gnuLongPath) { + this._header.name = this._gnuLongPath + this._gnuLongPath = null + } + + if (this._gnuLongLinkPath) { + this._header.linkname = this._gnuLongLinkPath + this._gnuLongLinkPath = null + } + + if (this._pax) { + if (this._pax.path) this._header.name = this._pax.path + if (this._pax.linkpath) this._header.linkname = this._pax.linkpath + if (this._pax.size) this._header.size = parseInt(this._pax.size, 10) + this._header.pax = this._pax + this._pax = null + } + } + + _decodeLongHeader (buf) { + switch (this._header.type) { + case 'gnu-long-path': + this._gnuLongPath = headers.decodeLongPath(buf, this._filenameEncoding) + break + case 'gnu-long-link-path': + this._gnuLongLinkPath = headers.decodeLongPath(buf, this._filenameEncoding) + break + case 'pax-global-header': + this._paxGlobal = headers.decodePax(buf) + break + case 'pax-header': + this._pax = this._paxGlobal === null + ? headers.decodePax(buf) + : Object.assign({}, this._paxGlobal, headers.decodePax(buf)) + break + } + } + + _consumeLongHeader () { + this._longHeader = false + this._missing = overflow(this._header.size) + + const buf = this._buffer.shift(this._header.size) + + try { + this._decodeLongHeader(buf) + } catch (err) { + this._continueWrite(err) + return false + } + + return true + } + + _consumeStream () { + const buf = this._buffer.shiftFirst(this._missing) + if (buf === null) return false + + this._missing -= buf.byteLength + const drained = this._stream.push(buf) + + if (this._missing === 0) { + this._stream.push(null) + if (drained) this._stream._detach() + return drained && this._locked === false + } + + return drained + } + + _createStream () { + return new Source(this, this._header, this._offset) + } + + _update () { + while (this._buffer.buffered > 0 && !this.destroying) { + if (this._missing > 0) { + if (this._stream !== null) { + if (this._consumeStream() === false) return + continue + } + + if (this._longHeader === true) { + if (this._missing > this._buffer.buffered) break + if (this._consumeLongHeader() === false) return false + continue + } + + const ignore = this._buffer.shiftFirst(this._missing) + if (ignore !== null) this._missing -= ignore.byteLength + continue + } + + if (this._buffer.buffered < 512) break + if (this._stream !== null || this._consumeHeader() === false) return + } + + this._continueWrite(null) + } + + _continueWrite (err) { + const cb = this._callback + this._callback = noop + cb(err) + } + + _write (data, encoding, cb) { + this._callback = cb + this._buffer.push(data) + this._update() + } + + _final (cb) { + this._finished = this._missing === 0 && this._buffer.buffered === 0 + cb(this._finished ? null : new Error('Unexpected end of data')) + } + + _predestroy () { + this._continueWrite(null) + } + + _destroy (err, cb) { + if (this._stream) this._stream.destroy(err) + cb(null) + } +} + +module.exports = function extract (opts) { + return new Extract(opts) +} + +function noop () {} + +function overflow (size) { + size &= 511 + return size && 512 - size +} diff --git a/packages/playwright-core/src/utils/tar/headers.js b/packages/playwright-core/src/utils/tar/headers.js new file mode 100644 index 0000000000..8e03afc530 --- /dev/null +++ b/packages/playwright-core/src/utils/tar/headers.js @@ -0,0 +1,225 @@ +const ZERO_OFFSET = '0'.charCodeAt(0) +const USTAR_MAGIC = Buffer.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x00]) // ustar\x00 +const GNU_MAGIC = Buffer.from([0x75, 0x73, 0x74, 0x61, 0x72, 0x20]) // ustar\x20 +const GNU_VER = Buffer.from([0x20, 0x00]) +const MAGIC_OFFSET = 257 +const VERSION_OFFSET = 263 + +exports.decodeLongPath = function decodeLongPath (buf, encoding) { + return decodeStr(buf, 0, buf.length, encoding) +} + +exports.encodePax = function encodePax (opts) { // TODO: encode more stuff in pax + let result = '' + if (opts.name) result += addLength(' path=' + opts.name + '\n') + if (opts.linkname) result += addLength(' linkpath=' + opts.linkname + '\n') + const pax = opts.pax + if (pax) { + for (const key in pax) { + result += addLength(' ' + key + '=' + pax[key] + '\n') + } + } + return Buffer.from(result) +} + +exports.decodePax = function decodePax (buf) { + const result = {} + + while (buf.length) { + let i = 0 + while (i < buf.length && buf[i] !== 32) i++ + const len = parseInt(buf.toString('ascii', 0, i), 10) + if (!len) return result + + const b = buf.subarray('ascii', i + 1, len - 1) + const keyIndex = b.indexOf('=') + if (keyIndex === -1) return result + result[b.slice(0, keyIndex)] = b.slice(keyIndex + 1) + + buf = buf.subarray(len) + } + + return result +} + +exports.decode = function decode (buf, filenameEncoding, allowUnknownFormat) { + let typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET + + let name = decodeStr(buf, 0, 100, filenameEncoding) + const mode = decodeOct(buf, 100, 8) + const uid = decodeOct(buf, 108, 8) + const gid = decodeOct(buf, 116, 8) + const size = decodeOct(buf, 124, 12) + const mtime = decodeOct(buf, 136, 12) + const type = toType(typeflag) + const linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100, filenameEncoding) + const uname = decodeStr(buf, 265, 32) + const gname = decodeStr(buf, 297, 32) + const devmajor = decodeOct(buf, 329, 8) + const devminor = decodeOct(buf, 337, 8) + + const c = cksum(buf) + + // checksum is still initial value if header was null. + if (c === 8 * 32) return null + + // valid checksum + if (c !== decodeOct(buf, 148, 8)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?') + + if (isUSTAR(buf)) { + // ustar (posix) format. + // prepend prefix, if present. + if (buf[345]) name = decodeStr(buf, 345, 155, filenameEncoding) + '/' + name + } else if (isGNU(buf)) { + // 'gnu'/'oldgnu' format. Similar to ustar, but has support for incremental and + // multi-volume tarballs. + } else { + if (!allowUnknownFormat) { + throw new Error('Invalid tar header: unknown format.') + } + } + + // to support old tar versions that use trailing / to indicate dirs + if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5 + + return { + name, + mode, + uid, + gid, + size, + mtime: new Date(1000 * mtime), + type, + linkname, + uname, + gname, + devmajor, + devminor, + pax: null + } +} + +function isUSTAR (buf) { + return USTAR_MAGIC.equals(buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)) +} + +function isGNU (buf) { + return GNU_MAGIC.equals(buf.subarray(MAGIC_OFFSET, MAGIC_OFFSET + 6)) && + GNU_VER.equals(buf.subarray(VERSION_OFFSET, VERSION_OFFSET + 2)) +} + +function clamp (index, len, defaultValue) { + if (typeof index !== 'number') return defaultValue + index = ~~index // Coerce to integer. + if (index >= len) return len + if (index >= 0) return index + index += len + if (index >= 0) return index + return 0 +} + +function toType (flag) { + switch (flag) { + case 0: + return 'file' + case 1: + return 'link' + case 2: + return 'symlink' + case 3: + return 'character-device' + case 4: + return 'block-device' + case 5: + return 'directory' + case 6: + return 'fifo' + case 7: + return 'contiguous-file' + case 72: + return 'pax-header' + case 55: + return 'pax-global-header' + case 27: + return 'gnu-long-link-path' + case 28: + case 30: + return 'gnu-long-path' + } + + return null +} + +function indexOf (block, num, offset, end) { + for (; offset < end; offset++) { + if (block[offset] === num) return offset + } + return end +} + +function cksum (block) { + let sum = 8 * 32 + for (let i = 0; i < 148; i++) sum += block[i] + for (let j = 156; j < 512; j++) sum += block[j] + return sum +} + +/* Copied from the node-tar repo and modified to meet + * tar-stream coding standard. + * + * Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349 + */ +function parse256 (buf) { + // first byte MUST be either 80 or FF + // 80 for positive, FF for 2's comp + let positive + if (buf[0] === 0x80) positive = true + else if (buf[0] === 0xFF) positive = false + else return null + + // build up a base-256 tuple from the least sig to the highest + const tuple = [] + let i + for (i = buf.length - 1; i > 0; i--) { + const byte = buf[i] + if (positive) tuple.push(byte) + else tuple.push(0xFF - byte) + } + + let sum = 0 + const l = tuple.length + for (i = 0; i < l; i++) { + sum += tuple[i] * Math.pow(256, i) + } + + return positive ? sum : -1 * sum +} + +function decodeOct (val, offset, length) { + val = val.subarray(offset, offset + length) + offset = 0 + + // If prefixed with 0x80 then parse as a base-256 integer + if (val[offset] & 0x80) { + return parse256(val) + } else { + // Older versions of tar can prefix with spaces + while (offset < val.length && val[offset] === 32) offset++ + const end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length) + while (offset < end && val[offset] === 0) offset++ + if (end === offset) return 0 + return parseInt(val.toString('ascii', offset, end), 8) + } +} + +function decodeStr (val, offset, length, encoding) { + return val.toString(encoding, offset, indexOf(val, 0, offset, offset + length)) +} + +function addLength (str) { + const len = Buffer.byteLength(str) + let digits = Math.floor(Math.log(len) / Math.log(10)) + 1 + if (len + digits >= Math.pow(10, digits)) digits++ + + return (len + digits) + str +} diff --git a/packages/playwright-core/src/utils/tar/index.js b/packages/playwright-core/src/utils/tar/index.js new file mode 100644 index 0000000000..812a9ed0f7 --- /dev/null +++ b/packages/playwright-core/src/utils/tar/index.js @@ -0,0 +1,238 @@ +const tarExtract = require('./extract') +const fs = require('fs') +const path = require('path') +const { pipeline } = require('stream/promises') + +const win32 = process.platform === 'win32' + + +function head (list) { + return list.length ? list[list.length - 1] : null +} + +function processGetuid () { + return process.getuid ? process.getuid() : -1 +} + +function processUmask () { + return process.umask ? process.umask() : 0 +} + +exports.extract = function extract (cwd, opts) { + if (!cwd) cwd = '.' + if (!opts) opts = {} + + const xfs = opts.fs || fs + const ignore = opts.ignore || opts.filter || noop + const mapStream = opts.mapStream || echo + const own = opts.chown !== false && !win32 && processGetuid() === 0 + const extract = opts.extract || tarExtract() + const stack = [] + const now = new Date() + const umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask() + const strict = opts.strict !== false + + let map = opts.map || noop + let dmode = typeof opts.dmode === 'number' ? opts.dmode : 0 + let fmode = typeof opts.fmode === 'number' ? opts.fmode : 0 + + if (opts.strip) map = strip(map, opts.strip) + + if (opts.readable) { + dmode |= parseInt(555, 8) + fmode |= parseInt(444, 8) + } + if (opts.writable) { + dmode |= parseInt(333, 8) + fmode |= parseInt(222, 8) + } + + extract.on('entry', onentry) + + if (opts.finish) extract.on('finish', opts.finish) + + return extract + + function onentry (header, stream, next) { + header = map(header) || header + header.name = normalize(header.name) + + const name = path.join(cwd, path.join('/', header.name)) + + if (ignore(name, header)) { + stream.resume() + return next() + } + + if (header.type === 'directory') { + stack.push([name, header.mtime]) + return mkdirfix(name, { + fs: xfs, + own, + uid: header.uid, + gid: header.gid, + mode: header.mode + }, stat) + } + + const dir = path.dirname(name) + + validate(xfs, dir, path.join(cwd, '.'), function (err, valid) { + if (err) return next(err) + if (!valid) return next(new Error(dir + ' is not a valid path')) + + mkdirfix(dir, { + fs: xfs, + own, + uid: header.uid, + gid: header.gid, + // normally, the folders with rights and owner should be part of the TAR file + // if this is not the case, create folder for same user as file and with + // standard permissions of 0o755 (rwxr-xr-x) + mode: 0o755 + }, function (err) { + if (err) return next(err) + + switch (header.type) { + case 'file': return onfile() + case 'link': return onlink() + case 'symlink': return onsymlink() + } + + if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')')) + + stream.resume() + next() + }) + }) + + function stat (err) { + if (err) return next(err) + utimes(name, header, function (err) { + if (err) return next(err) + if (win32) return next() + chperm(name, header, next) + }) + } + + function onsymlink () { + if (win32) return next() // skip symlinks on win for now before it can be tested + xfs.unlink(name, function () { + xfs.symlink(header.linkname, name, stat) + }) + } + + function onlink () { + if (win32) return next() // skip links on win for now before it can be tested + xfs.unlink(name, function () { + const srcpath = path.join(cwd, path.join('/', header.linkname)) + + xfs.link(srcpath, name, function (err) { + if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) { + stream = xfs.createReadStream(srcpath) + return onfile() + } + + stat(err) + }) + }) + } + + function onfile () { + const ws = xfs.createWriteStream(name) + const rs = mapStream(stream, header) + + ws.on('error', function (err) { // always forward errors on destroy + rs.destroy(err) + }) + + pipeline(rs, ws).then(stat).catch(next); + } + } + + function utimesParent (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry + let top + while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop() + if (!top) return cb() + xfs.utimes(top[0], now, top[1], cb) + } + + function utimes (name, header, cb) { + if (opts.utimes === false) return cb() + + if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb) + if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link? + + xfs.utimes(name, now, header.mtime, function (err) { + if (err) return cb(err) + utimesParent(name, cb) + }) + } + + function chperm (name, header, cb) { + const link = header.type === 'symlink' + + /* eslint-disable n/no-deprecated-api */ + const chmod = link ? xfs.lchmod : xfs.chmod + const chown = link ? xfs.lchown : xfs.chown + /* eslint-enable n/no-deprecated-api */ + + if (!chmod) return cb() + + const mode = (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask + + if (chown && own) chown.call(xfs, name, header.uid, header.gid, onchown) + else onchown(null) + + function onchown (err) { + if (err) return cb(err) + if (!chmod) return cb() + chmod.call(xfs, name, mode, cb) + } + } + + function mkdirfix (name, opts, cb) { + // when mkdir is called on an existing directory, the permissions + // will be overwritten (?), to avoid this we check for its existance first + xfs.stat(name, function (err) { + if (!err) return cb(null) + if (err.code !== 'ENOENT') return cb(err) + xfs.mkdir(name, { mode: opts.mode, recursive: true }, function (err, made) { + if (err) return cb(err) + chperm(name, opts, cb) + }) + }) + } +} + +function validate (fs, name, root, cb) { + if (name === root) return cb(null, true) + fs.lstat(name, function (err, st) { + if (err && err.code === 'ENOENT') return validate(fs, path.join(name, '..'), root, cb) + else if (err) return cb(err) + cb(null, st.isDirectory()) + }) +} + +function noop () {} + +function echo (name) { + return name +} + +function normalize (name) { + return win32 ? name.replace(/\\/g, '/').replace(/[:?<>|]/g, '_') : name +} + +function strip (map, level) { + return function (header) { + header.name = header.name.split('/').slice(level).join('/') + + const linkname = header.linkname + if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) { + header.linkname = linkname.split('/').slice(level).join('/') + } + + return map(header) + } +} diff --git a/packages/playwright-core/src/zipBundle.ts b/packages/playwright-core/src/zipBundle.ts index b8fca6c710..9c275873a8 100644 --- a/packages/playwright-core/src/zipBundle.ts +++ b/packages/playwright-core/src/zipBundle.ts @@ -19,4 +19,3 @@ export type { ZipFile } from '../bundles/zip/node_modules/@types/yazl'; export const yauzl: typeof import('../bundles/zip/node_modules/@types/yauzl') = require('./zipBundleImpl').yauzl; export type { ZipFile as UnzipFile, Entry } from '../bundles/zip/node_modules/@types/yauzl'; export const extract: typeof import('../bundles/zip/node_modules/extract-zip') = require('./zipBundleImpl').extract; -export const tarFs = require('./zipBundleImpl').tarFs;