From 01fa1bc270eeb450686195ac652174e8e82abf8e Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 18:29:04 +0300 Subject: [PATCH 1/7] chore: update @yao-pkg/pkg --- package-lock.json | 413 +++++++++++++++++++++------------------------- package.json | 2 +- 2 files changed, 192 insertions(+), 223 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3251472c3..9bd96499c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@types/react-dom": "^19.2.3", "@types/react-router-dom": "^5.3.3", "@types/strip-comments": "^2.0.4", - "@yao-pkg/pkg": "^6.18.2", + "@yao-pkg/pkg": "^6.19.0", "esbuild": "^0.28.0", "esbuild-node-externals": "^1.22.0", "eslint": "^10.2.1", @@ -1989,9 +1989,9 @@ "license": "MIT" }, "node_modules/@roberts_lando/vfs": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@roberts_lando/vfs/-/vfs-0.3.2.tgz", - "integrity": "sha512-whXj9v78S4n3t0RvoTGj8vui27VVtK/oy8YfBL+gDWdlfRFkKpPjry+U8p+3XM++5rAIpXEtXcTUgUAEHZVoFA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@roberts_lando/vfs/-/vfs-0.3.3.tgz", + "integrity": "sha512-YjkxVSLw5WMZQoARaryRAjcxA+GbBzWMJdwYZX5oLUt9cC/gew9as4Dn7tcLzPp7BPoR221VpTZ+78TRPawnjg==", "dev": true, "license": "MIT", "engines": { @@ -3069,9 +3069,9 @@ "peer": true }, "node_modules/@yao-pkg/pkg": { - "version": "6.18.2", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.18.2.tgz", - "integrity": "sha512-lo+fNeV10ldTeTrDbgK2eYTIhKDqCUVVq7a4W3s7LiTwd9/8UKYdxBodVNNCbEd2JBtqKA4BZpevitfsOzyXig==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.19.0.tgz", + "integrity": "sha512-Ys9Fn/F44C3nOTlNyhwviLyMxydgFzsB13jAAXKxEuIR7aAz8PrFlUpxTUlwaXUU847nlmg5mnaGIyOJpnVtRw==", "dev": true, "license": "MIT", "dependencies": { @@ -3079,11 +3079,10 @@ "@babel/parser": "^7.23.0", "@babel/traverse": "^7.23.0", "@babel/types": "^7.23.0", - "@roberts_lando/vfs": "^0.3.2", + "@roberts_lando/vfs": "^0.3.3", "@yao-pkg/pkg-fetch": "3.5.33", "esbuild": "^0.27.3", "into-stream": "^9.1.0", - "minimist": "^1.2.6", "multistream": "^4.1.0", "picocolors": "^1.1.0", "picomatch": "^4.0.2", @@ -3144,13 +3143,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/@yao-pkg/pkg-fetch/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/@yao-pkg/pkg-fetch/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -3818,9 +3810,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3854,9 +3846,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "peer": true, @@ -4141,9 +4133,9 @@ } }, "node_modules/bare-os": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz", - "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.0.tgz", + "integrity": "sha512-JTjuZyNIDpw+GytMO4a6TK1VXdVKKJr6DRxEHasyuYyShV2deuiHJK/ahGZlebc+SG0/wJCB9XK8gprBGDFi/Q==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4188,9 +4180,9 @@ } }, "node_modules/bare-url": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.1.tgz", - "integrity": "sha512-fZapLWNB25gS+etK27NV9KgBNXgo2yeYHuj+OyPblQd6GYAE3JVy6aKxszMV5jhGGFwraXQKA5fldvf3lMyEqw==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz", + "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4219,9 +4211,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.20", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", - "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "version": "2.10.22", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.22.tgz", + "integrity": "sha512-6qruVrb5rse6WylFkU0FhBKKGuecWseqdpQfhkawn6ztyk2QlfwSRjsDxMCLJrkfmfN21qvhl9ABgaMeRkuwww==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4452,9 +4444,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001788", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", - "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "version": "1.0.30001790", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", + "integrity": "sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==", "dev": true, "funding": [ { @@ -4589,23 +4581,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4629,12 +4604,6 @@ "node": ">=8" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5065,9 +5034,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.340", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", - "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "version": "1.5.344", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", + "integrity": "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==", "dev": true, "license": "ISC" }, @@ -5084,6 +5053,12 @@ "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/empathic": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", @@ -5115,14 +5090,14 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz", + "integrity": "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" @@ -5517,13 +5492,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/exit-x": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", @@ -5766,6 +5734,33 @@ "dev": true, "license": "ISC" }, + "node_modules/foreground-child": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-4.0.3.tgz", + "integrity": "sha512-yeXZaNbCBGaT9giTpLPBdtedzjwhlJBUoL/R4BVQU5mn0TQXOHwVIl1Q2DMuBIdNno4ktA1abZ7dQFVxD6uHxw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -7210,66 +7205,10 @@ "node": ">=20.0.0" } }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, "license": "MIT", "peer": true, @@ -7359,13 +7298,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -7383,42 +7315,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", @@ -7682,21 +7578,6 @@ "mcr": "lib/cli.js" } }, - "node_modules/monocart-coverage-reports/node_modules/foreground-child": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-4.0.3.tgz", - "integrity": "sha512-yeXZaNbCBGaT9giTpLPBdtedzjwhlJBUoL/R4BVQU5mn0TQXOHwVIl1Q2DMuBIdNno4ktA1abZ7dQFVxD6uHxw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/monocart-locator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/monocart-locator/-/monocart-locator-1.0.3.tgz", @@ -7824,9 +7705,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", "dev": true, "license": "MIT" }, @@ -8859,6 +8740,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -8949,9 +8843,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "peer": true, @@ -9161,16 +9055,11 @@ } }, "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -9450,6 +9339,23 @@ "node": ">=8" } }, + "node_modules/string-width": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -9550,9 +9456,9 @@ } }, "node_modules/tapable": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", - "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -9629,9 +9535,9 @@ } }, "node_modules/terser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", - "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "version": "5.46.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz", + "integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==", "dev": true, "license": "BSD-2-Clause", "peer": true, @@ -9649,9 +9555,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==", "dev": true, "license": "MIT", "peer": true, @@ -10401,9 +10307,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.0.tgz", + "integrity": "sha512-gHwIe1cgBvvfLeu1Yz/dcFpmHfKDVxxyqI+kzqmuxZED81z2ChxpyqPaWcNqigPywhaEke7AjSGga+kxY55gjQ==", "dev": true, "license": "MIT", "peer": true, @@ -10481,6 +10387,62 @@ "dev": true, "license": "MIT" }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -10502,6 +10464,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -10570,12 +10545,6 @@ "node": ">=8" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", diff --git a/package.json b/package.json index f75d951fd..c6d07ec36 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@types/react-dom": "^19.2.3", "@types/react-router-dom": "^5.3.3", "@types/strip-comments": "^2.0.4", - "@yao-pkg/pkg": "^6.18.2", + "@yao-pkg/pkg": "^6.19.0", "esbuild": "^0.28.0", "esbuild-node-externals": "^1.22.0", "eslint": "^10.2.1", From a549271c5ba49019df42635a4dc6d55fa53926bb Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 18:38:44 +0300 Subject: [PATCH 2/7] chore: add test-app logging --- atest/library/common.py | 28 +++++++-- node/dynamic-test-app/src/server.ts | 2 + package-lock.json | 89 +++++++++++++++++++++++++++++ package.json | 2 + 4 files changed, 115 insertions(+), 6 deletions(-) diff --git a/atest/library/common.py b/atest/library/common.py index ae532226b..dd925486f 100644 --- a/atest/library/common.py +++ b/atest/library/common.py @@ -1,7 +1,7 @@ import os from pathlib import Path -from subprocess import PIPE, STDOUT, Popen -from typing import Dict, NamedTuple +from subprocess import STDOUT, Popen +from typing import IO, Dict, NamedTuple from urllib.parse import urlparse from robot.api import logger @@ -10,6 +10,13 @@ from Browser.utils import FormatterKeywords, close_process_tree, find_free_port SERVERS: Dict = {} +LOG_FILES: Dict[str, IO] = {} + + +def _open_test_app_log(root_dir: Path, port: str) -> IO: + log_dir = root_dir / "atest" / "output" / "test-app" + log_dir.mkdir(parents=True, exist_ok=True) + return open(log_dir / f"test-app-{port}.log", "w", encoding="utf-8") def parse_url(url: str) -> NamedTuple: @@ -17,20 +24,22 @@ def parse_url(url: str) -> NamedTuple: def start_test_server(): - global SERVERS + global SERVERS, LOG_FILES port = str(find_free_port()) # For some reason, we need to have cwd at project root for the server to run properly. root_dir = Path(os.path.dirname(__file__)) / ".." / ".." root_dir = root_dir.resolve() test_app_path = root_dir / "node" / "dynamic-test-app" / "dist" / "server.js" print(test_app_path) + log_file = _open_test_app_log(root_dir, port) process = Popen( ["node", test_app_path, "-p", port], - stdout=PIPE, + stdout=log_file, stderr=STDOUT, cwd=str(root_dir), ) SERVERS[port] = process + LOG_FILES[port] = log_file return port @@ -59,6 +68,7 @@ def start_test_https_server( ca_cert_path = os.path.relpath(os.path.abspath(ca_cert_path), start=test_app_dir) print(test_app_path) + log_file = _open_test_app_log(root_dir, port) process = Popen( [ "node", @@ -73,21 +83,27 @@ def start_test_https_server( ca_cert_path, "-M" if mutual_tls else "-T", ], - text=True, + stdout=log_file, + stderr=STDOUT, cwd=str(root_dir), ) SERVERS[port] = process + LOG_FILES[port] = log_file return port def stop_test_server(port: str): - global SERVERS + global SERVERS, LOG_FILES if port in SERVERS: p: Popen = SERVERS[port] close_process_tree(p) del SERVERS[port] else: logger.warn(f"Server with port {port} not found") + if port in LOG_FILES: + LOG_FILES[port].flush() + LOG_FILES[port].close() + del LOG_FILES[port] def get_current_scope_from_lib(keyword: FormatterKeywords) -> list: diff --git a/node/dynamic-test-app/src/server.ts b/node/dynamic-test-app/src/server.ts index d8d38d279..de77b68c1 100644 --- a/node/dynamic-test-app/src/server.ts +++ b/node/dynamic-test-app/src/server.ts @@ -2,10 +2,12 @@ import { Command } from 'commander'; import * as express from 'express'; import * as fs from 'fs'; import * as https from 'https'; +import * as morgan from 'morgan'; import * as path from 'path'; const app = express.default(); +app.use(morgan.default(':date[iso] :method :url :status :res[content-length] - :response-time ms')); app.use(express.json()); const program = new Command(); diff --git a/package-lock.json b/package-lock.json index 9bd96499c..80a082f15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@eslint/js": "^10.0.1", "@types/express": "^5.0.6", "@types/jest": "^30.0.0", + "@types/morgan": "^1.9.9", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@types/react-router-dom": "^5.3.3", @@ -40,6 +41,7 @@ "husky": "^9.1.7", "jest": "^30.3.0", "lint-staged": "^16.4.0", + "morgan": "^1.10.0", "prettier": "^3.8.3", "react": "^19.2.5", "react-dnd": "^16.0.1", @@ -2252,6 +2254,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/morgan": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz", + "integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "25.6.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", @@ -4223,6 +4235,26 @@ "node": ">=6.0.0" } }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -7584,6 +7616,53 @@ "integrity": "sha512-pe29W2XAoA1WQmZZqxXoP7s06ZEXUhcb81086v68cqjk1HnVL7Q/iU/WJnnetxjPcLqwb4qG8vaSGUOMQU602g==", "license": "MIT" }, + "node_modules/morgan": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7785,6 +7864,16 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index c6d07ec36..a9c984277 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/express": "^5.0.6", + "@types/morgan": "^1.9.9", "@types/jest": "^30.0.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", @@ -24,6 +25,7 @@ "husky": "^9.1.7", "jest": "^30.3.0", "lint-staged": "^16.4.0", + "morgan": "^1.10.0", "prettier": "^3.8.3", "react": "^19.2.5", "react-dnd": "^16.0.1", From 9ec2cfab194cdfc6afe632ac0862d998ec9acebc Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 19:56:20 +0300 Subject: [PATCH 3/7] chore: get dokcer logs always --- .github/workflows/on-push.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index f3a8e7ee0..96862974c 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -519,8 +519,17 @@ jobs: pip install uv uv pip install invoke robotframework-ghareports --python 3.14 --system invoke run-test-app-no-build --asynchronous - docker run -v ./atest/:/home/pwuser/test -t tidii:latest bash -c "robot -v SERVER:172.17.0.1:7272 --exclude no-docker-pr -L debug --outputdir /home/pwuser/output /home/pwuser/test" + set +e + docker run -v ./atest/:/home/pwuser/test -t tidii:latest bash -c "robot -v SERVER:172.17.0.1:7272 --exclude no-docker-pr -L debug --outputdir /home/pwuser/output /home/pwuser/test" + docker_status=$? inv docker-copy-output + exit $docker_status + + - uses: actions/upload-artifact@v7 + if: ${{ always() }} + with: + name: docker_results + path: output_docker - name: Github Job Summary if: ${{ always() }} run: | From 614865e2f0381ecd7a97aeb53cf8f79c651306ae Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 20:02:51 +0300 Subject: [PATCH 4/7] chore: review fixes --- .github/workflows/on-push.yml | 6 +++- atest/library/common.py | 56 ++++++++++++++++------------- node/dynamic-test-app/src/server.ts | 4 +-- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index 96862974c..296773aa1 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -523,7 +523,11 @@ jobs: docker run -v ./atest/:/home/pwuser/test -t tidii:latest bash -c "robot -v SERVER:172.17.0.1:7272 --exclude no-docker-pr -L debug --outputdir /home/pwuser/output /home/pwuser/test" docker_status=$? inv docker-copy-output - exit $docker_status + copy_status=$? + if [ "$docker_status" -ne 0 ]; then + exit "$docker_status" + fi + exit "$copy_status" - uses: actions/upload-artifact@v7 if: ${{ always() }} diff --git a/atest/library/common.py b/atest/library/common.py index dd925486f..41edef80f 100644 --- a/atest/library/common.py +++ b/atest/library/common.py @@ -32,12 +32,16 @@ def start_test_server(): test_app_path = root_dir / "node" / "dynamic-test-app" / "dist" / "server.js" print(test_app_path) log_file = _open_test_app_log(root_dir, port) - process = Popen( - ["node", test_app_path, "-p", port], - stdout=log_file, - stderr=STDOUT, - cwd=str(root_dir), - ) + try: + process = Popen( + ["node", test_app_path, "-p", port], + stdout=log_file, + stderr=STDOUT, + cwd=str(root_dir), + ) + except Exception: + log_file.close() + raise SERVERS[port] = process LOG_FILES[port] = log_file return port @@ -69,24 +73,28 @@ def start_test_https_server( print(test_app_path) log_file = _open_test_app_log(root_dir, port) - process = Popen( - [ - "node", - test_app_path, - "-p", - port, - "-c", - server_cert_path, - "-k", - server_key_path, - "-C", - ca_cert_path, - "-M" if mutual_tls else "-T", - ], - stdout=log_file, - stderr=STDOUT, - cwd=str(root_dir), - ) + try: + process = Popen( + [ + "node", + test_app_path, + "-p", + port, + "-c", + server_cert_path, + "-k", + server_key_path, + "-C", + ca_cert_path, + "-M" if mutual_tls else "-T", + ], + stdout=log_file, + stderr=STDOUT, + cwd=str(root_dir), + ) + except Exception: + log_file.close() + raise SERVERS[port] = process LOG_FILES[port] = log_file return port diff --git a/node/dynamic-test-app/src/server.ts b/node/dynamic-test-app/src/server.ts index de77b68c1..e56428e7b 100644 --- a/node/dynamic-test-app/src/server.ts +++ b/node/dynamic-test-app/src/server.ts @@ -2,12 +2,12 @@ import { Command } from 'commander'; import * as express from 'express'; import * as fs from 'fs'; import * as https from 'https'; -import * as morgan from 'morgan'; +import morgan from 'morgan'; import * as path from 'path'; const app = express.default(); -app.use(morgan.default(':date[iso] :method :url :status :res[content-length] - :response-time ms')); +app.use(morgan(':date[iso] :method :url :status :res[content-length] - :response-time ms')); app.use(express.json()); const program = new Command(); From ee5e0229b0f6bdaee64ae7b783bab5e481e814d9 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 20:06:09 +0300 Subject: [PATCH 5/7] chore: remove unused // @ts-expect-error --- node/dynamic-test-app/src/server.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/node/dynamic-test-app/src/server.ts b/node/dynamic-test-app/src/server.ts index e56428e7b..bacc74227 100644 --- a/node/dynamic-test-app/src/server.ts +++ b/node/dynamic-test-app/src/server.ts @@ -33,9 +33,7 @@ const mutualTls: boolean = options.mutualTls; app.set('etag', false); -// @ts-expect-error app.get('/favicon.ico', (req, res) => res.status(204).send()); -// @ts-expect-error app.get('/dist/favicon.ico', (req, res) => res.status(204).send()); app.head('/api/get/json', (req, res) => { From 6b26ab40385aa595bf48abab980e9476ec081ca3 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 20:11:51 +0300 Subject: [PATCH 6/7] fix: make starting playwright more robust --- Browser/playwright.py | 68 ++++++++++++++++++++++++++++++++------ utest/test_python_usage.py | 24 ++++++++++++++ 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/Browser/playwright.py b/Browser/playwright.py index 68719c8b0..48d6567be 100644 --- a/Browser/playwright.py +++ b/Browser/playwright.py @@ -55,6 +55,7 @@ class Playwright(LibraryComponent): """A wrapper for communicating with nodejs Playwright process.""" port: str | None + _node_dependencies_checked = False def __init__( self, @@ -66,19 +67,38 @@ def __init__( ): LibraryComponent.__init__(self, library) self.enable_playwright_debug = enable_playwright_debug - self.ensure_node_dependencies() self.host = str(host) if host else None self.port = str(port) if port else None + self.ensure_node_dependencies() self.playwright_log = playwright_log @cached_property def _playwright_process(self) -> Popen | None: - process = self.start_playwright() - atexit.register(self.close) - self.wait_until_server_up() - if platform.system() == "Darwin": - time.sleep(1) # To overcome problem with macOS Sonoma and hanging process - return process + max_attempts = 2 if platform.system() == "Darwin" else 1 + last_error: RuntimeError | None = None + for attempt in range(1, max_attempts + 1): + process = self.start_playwright() + try: + self.wait_until_server_up() + atexit.register(self.close) + if platform.system() == "Darwin": + time.sleep( + 1 + ) # To overcome problem with macOS Sonoma and hanging process + return process + except RuntimeError as err: + last_error = err + if process: + close_process_tree(process) + # Reset host/port so next attempt starts a fresh process on a fresh port. + self.host = None + self.port = None + if attempt < max_attempts: + logger.info( + "Retrying Playwright startup on macOS after initial startup failure" + ) + time.sleep(0.25) + raise last_error if last_error else RuntimeError("Failed to start Playwright") @cached_property def _rfbrowser_dir(self) -> Path: @@ -93,18 +113,43 @@ def ensure_node_dependencies(self): If BrowserBatteries is installed, does nothing. """ + if self.__class__._node_dependencies_checked: + return if start_grpc_server is not None: logger.trace( "Running gRPC server from BrowserBatteries, no need to check node" ) + self.__class__._node_dependencies_checked = True return - try: - run(["node", "-v"], stdout=DEVNULL, check=True) - except (CalledProcessError, FileNotFoundError, PermissionError) as err: + + # If an external Playwright process is configured, this Python process + # acts only as a gRPC client and does not need to execute local `node`. + configured_port = getattr(self, "port", None) + if configured_port or os.environ.get("ROBOT_FRAMEWORK_BROWSER_NODE_PORT"): + logger.trace( + "Using external Playwright process, skipping local node dependency check" + ) + return + + node_check_error: ( + CalledProcessError | FileNotFoundError | PermissionError | None + ) = None + node_check_attempts = 3 if platform.system() == "Darwin" else 1 + for attempt in range(node_check_attempts): + try: + run(["node", "-v"], stdout=DEVNULL, check=True) + node_check_error = None + break + except (CalledProcessError, FileNotFoundError, PermissionError) as err: + node_check_error = err + if attempt < node_check_attempts - 1: + time.sleep(0.2) + + if node_check_error is not None: raise RuntimeError( "Couldn't execute node. Please ensure you have node.js installed and in PATH. " "See https://nodejs.org/ for instructions. " - f"Original error is {err}" + f"Original error is {node_check_error}" ) # This second application of .parent is necessary to find out that a developer setup has node_modules correctly @@ -115,6 +160,7 @@ def ensure_node_dependencies(self): (self._browser_wrapper_dir / "node_modules").is_dir(), ] ): + self.__class__._node_dependencies_checked = True return raise RuntimeError( diff --git a/utest/test_python_usage.py b/utest/test_python_usage.py index 92795725b..dfc828a5c 100644 --- a/utest/test_python_usage.py +++ b/utest/test_python_usage.py @@ -102,6 +102,30 @@ def test_playwright_lazy_initialization(browser): assert isinstance(browser.playwright, Browser.playwright.Playwright) +def test_playwright_constructor_port_skips_local_node_check(monkeypatch): + monkeypatch.setattr( + Browser.playwright.Playwright, "_node_dependencies_checked", False + ) + monkeypatch.setattr(Browser.playwright, "start_grpc_server", None) + monkeypatch.delenv("ROBOT_FRAMEWORK_BROWSER_NODE_PORT", raising=False) + + def _fail_if_node_check_called(*args, **kwargs): + raise AssertionError( + "Local node check should be skipped when external port is configured" + ) + + monkeypatch.setattr(Browser.playwright, "run", _fail_if_node_check_called) + + pw = Browser.playwright.Playwright( + library=Mock(), + enable_playwright_debug=False, + host=None, + port=12345, + ) + + assert pw.port == "12345" + + def test_open_page_get_text(application_server, browser): browser.new_page("localhost:7272/dist/") text = browser.get_text("h1", AssertionOperator["=="], "Login Page") From 845c40b2d1aa9bd7a1646a3af5370b1babd6e543 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Sat, 25 Apr 2026 20:22:49 +0300 Subject: [PATCH 7/7] fix: for docker stdout streaming --- node/dynamic-test-app/src/server.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/dynamic-test-app/src/server.ts b/node/dynamic-test-app/src/server.ts index bacc74227..62594feb7 100644 --- a/node/dynamic-test-app/src/server.ts +++ b/node/dynamic-test-app/src/server.ts @@ -7,7 +7,9 @@ import * as path from 'path'; const app = express.default(); -app.use(morgan(':date[iso] :method :url :status :res[content-length] - :response-time ms')); +// Configure morgan to write to a log file to avoid stdout blocking in Docker +const logStream = fs.createWriteStream(path.join(__dirname, '..', 'test-app.log'), { flags: 'a' }); +app.use(morgan(':date[iso] :method :url :status :res[content-length] - :response-time ms', { stream: logStream })); app.use(express.json()); const program = new Command();