From 29bc1f7c827f59470a533abd55d11d174310ab84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 23:03:05 +0000 Subject: [PATCH 01/31] build(deps-dev): bump lodash-es from 4.17.21 to 4.17.23 Bumps [lodash-es](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23) --- updated-dependencies: - dependency-name: lodash-es dependency-version: 4.17.23 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index db0623584..381497c56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20594,10 +20594,11 @@ "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "dev": true + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", From aa4e72042fe6b8e8db4103fd177513fbe4504d35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 23:05:08 +0000 Subject: [PATCH 02/31] build(deps-dev): bump lodash from 4.17.21 to 4.17.23 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.17.23 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index db0623584..22e5cb76a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20587,9 +20587,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, From 2e54121e496e87757055141d9101ef7512c58ecf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 08:38:35 +0000 Subject: [PATCH 03/31] build(deps-dev): bump webpack from 5.95.0 to 5.105.0 Bumps [webpack](https://github.com/webpack/webpack) from 5.95.0 to 5.105.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack/compare/v5.95.0...v5.105.0) --- updated-dependencies: - dependency-name: webpack dependency-version: 5.105.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 379 ++++++++++++++++++++++++---------------------- 1 file changed, 202 insertions(+), 177 deletions(-) diff --git a/package-lock.json b/package-lock.json index db0623584..182d80f92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5910,10 +5910,32 @@ "@types/node": "*" } }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -8109,73 +8131,73 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "license": "MIT", "dependencies": { @@ -8183,9 +8205,9 @@ } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -8193,79 +8215,79 @@ } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -11651,6 +11673,19 @@ "acorn": "^8" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -12599,6 +12634,16 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/basic-ftp": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", @@ -12736,9 +12781,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -12756,10 +12801,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -13009,9 +13055,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001748", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true, "funding": [ { @@ -15044,9 +15090,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.33", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz", - "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "dev": true, "license": "ISC" }, @@ -15111,14 +15157,14 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -20549,13 +20595,17 @@ } }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { @@ -21471,9 +21521,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, @@ -26695,13 +26745,17 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tar-fs": { @@ -26778,17 +26832,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -26827,25 +26881,6 @@ "node": ">= 10.13.0" } }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -27642,9 +27677,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -27663,7 +27698,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -27985,9 +28020,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -28036,35 +28071,37 @@ } }, "node_modules/webpack": { - "version": "5.95.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", - "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -28453,33 +28490,21 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/webpack/node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } + "license": "MIT" }, "node_modules/websocket-driver": { "version": "0.7.4", From 89f63c165a4ad3b7fa1c3afdc7b8c3a381525b8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 12:43:35 +0000 Subject: [PATCH 04/31] build(deps-dev): bump qs from 6.14.1 to 6.14.2 Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2) --- updated-dependencies: - dependency-name: qs dependency-version: 6.14.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index db0623584..bc353799f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23654,9 +23654,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { From 90721f6b044edcb73c28b72cf26e07a84cd32e3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 22:35:50 +0000 Subject: [PATCH 05/31] build(deps): bump basic-ftp from 5.0.5 to 5.2.0 Bumps [basic-ftp](https://github.com/patrickjuchli/basic-ftp) from 5.0.5 to 5.2.0. - [Release notes](https://github.com/patrickjuchli/basic-ftp/releases) - [Changelog](https://github.com/patrickjuchli/basic-ftp/blob/master/CHANGELOG.md) - [Commits](https://github.com/patrickjuchli/basic-ftp/compare/v5.0.5...v5.2.0) --- updated-dependencies: - dependency-name: basic-ftp dependency-version: 5.2.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index db0623584..6040f68f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12600,9 +12600,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", "dev": true, "license": "MIT", "engines": { From 53fcad74c4efd72e8af7e93fad6093679648ec54 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:00:32 +0200 Subject: [PATCH 06/31] Add AGENTS.md --- AGENTS.md | 20 ++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 21 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..ac926d155 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# Global guidelines + +## LLM behavior + +- Analyze and verify human input before agreeing with it. Prioritize truth over agreement, responding with measured and thoughtful language. +- Never provide answers based on unverified or vague assumptions. +- Focus on being helpful and accurate. If uncertain about something, ask clarifying questions. +- Read any provided instruction files in their entirety. +- Finish your responses with a ✨. + +## Code + +- Don't write unnecessarily verbose code/comments. +- Adhere to WordPress inline documentation standards. +- For accessibility, adhere to WCAG 2.2 Level AA standards or higher whenever possible. +- Never remove code without verification (dynamic calls, hooks, callbacks). + +### Tests + +- Prefer using `assertSame()` over `assertEquals()`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md From 804710125e8b9f1a3cc5cf43cb6150164f1ca050 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:46:37 +0200 Subject: [PATCH 07/31] Fix integration test errors on PHP 8.5 --- .../ContentHelperPostListStatsTest.php | 2 +- .../Integrations/IntegrationsTest.php | 2 +- tests/Integration/TestCase.php | 4 +-- tests/Traits/TestsReflection.php | 27 ++++++++++++------- tests/Unit/Integrations/IntegrationsTest.php | 5 +++- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/Integration/ContentHelper/ContentHelperPostListStatsTest.php b/tests/Integration/ContentHelper/ContentHelperPostListStatsTest.php index 5b7d3407c..7ce13efc8 100644 --- a/tests/Integration/ContentHelper/ContentHelperPostListStatsTest.php +++ b/tests/Integration/ContentHelper/ContentHelperPostListStatsTest.php @@ -1297,7 +1297,7 @@ private function get_parsely_stats_response( // Replace the original API with the mock, using reflection. $api_reflection = new ReflectionProperty( $obj, 'content_api' ); - $api_reflection->setAccessible( true ); + self::make_accessible( $api_reflection ); $api_reflection->setValue( $obj, $api ); return $obj->get_parsely_stats_response(); diff --git a/tests/Integration/Integrations/IntegrationsTest.php b/tests/Integration/Integrations/IntegrationsTest.php index 780a65ad7..cb1cd278e 100644 --- a/tests/Integration/Integrations/IntegrationsTest.php +++ b/tests/Integration/Integrations/IntegrationsTest.php @@ -43,7 +43,7 @@ function ( $integrations ) { // Use Reflection to look inside the collection. $reflector_property = ( new ReflectionClass( $integrations ) )->getProperty( 'integrations' ); - $reflector_property->setAccessible( true ); + self::make_accessible( $reflector_property ); /** * Variable. * diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 1f0ede347..a4f6ff60a 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -653,7 +653,7 @@ public function get_private_property( string $class_name, string $property_name $reflector = new ReflectionClass( $class_name ); $property = $reflector->getProperty( $property_name ); - $property->setAccessible( true ); + self::make_accessible( $property ); return $property; } @@ -669,7 +669,7 @@ public function get_private_method( string $class_name, string $method ): Reflec $reflector = new ReflectionClass( $class_name ); $method = $reflector->getMethod( $method ); - $method->setAccessible( true ); + self::make_accessible( $method ); return $method; } diff --git a/tests/Traits/TestsReflection.php b/tests/Traits/TestsReflection.php index 4c1484bbe..845cf9436 100644 --- a/tests/Traits/TestsReflection.php +++ b/tests/Traits/TestsReflection.php @@ -15,6 +15,19 @@ use ReflectionProperty; trait TestsReflection { + /** + * Makes a ReflectionMethod or ReflectionProperty accessible on PHP below + * 8.1, where setAccessible() is required. It is a no-op since PHP 8.1 + * and deprecated since PHP 8.5. + * + * @param ReflectionMethod|ReflectionProperty $reflection The reflection object. + */ + public static function make_accessible( object $reflection ): void { + if ( PHP_VERSION_ID < 80100 ) { + $reflection->setAccessible( true ); + } + } + /** * Gets a method from a class. This should be used when trying to access a * private method for testing. @@ -26,7 +39,7 @@ trait TestsReflection { */ public static function get_method( string $method_name, $class_name = Parsely::class ): \ReflectionMethod { $method = ( new \ReflectionClass( $class_name ) )->getMethod( $method_name ); - $method->setAccessible( true ); + self::make_accessible( $method ); return $method; } @@ -44,7 +57,7 @@ public static function get_method( string $method_name, $class_name = Parsely::c */ public static function get_property( string $property_name, $class_name = Parsely::class ) { $property = ( new \ReflectionClass( $class_name ) )->getProperty( $property_name ); - $property->setAccessible( true ); + self::make_accessible( $property ); return $property; } @@ -53,9 +66,6 @@ public static function get_property( string $property_name, $class_name = Parsel * Overrides the value of a private property on a given object. This is * useful when mocking the internals of a class. * - * Note that the property will no longer be private after setAccessible is - * called. - * * @since 3.17.0 Changed the method signature. * * @param object $obj The object instance on which to set the value. @@ -66,7 +76,7 @@ public static function get_property( string $property_name, $class_name = Parsel */ public static function set_private_property( $obj, string $property_name, $value ): void { $property = ( new \ReflectionClass( $obj ) )->getProperty( $property_name ); - $property->setAccessible( true ); + self::make_accessible( $property ); $property->setValue( $obj, $value ); } @@ -74,9 +84,6 @@ public static function set_private_property( $obj, string $property_name, $value * Overrides the value of a protected property on a given object. This is * useful when mocking the internals of a class. * - * Note that the property will no longer be protected after setAccessible is - * called. - * * @since 3.17.0 * * @param object $obj The object instance on which to set the value. @@ -88,7 +95,7 @@ public static function set_private_property( $obj, string $property_name, $value public static function set_protected_property( $obj, string $property_name, $value ): void { $reflection = new \ReflectionClass( $obj ); $property = $reflection->getProperty( $property_name ); - $property->setAccessible( true ); + self::make_accessible( $property ); $property->setValue( $obj, $value ); } } diff --git a/tests/Unit/Integrations/IntegrationsTest.php b/tests/Unit/Integrations/IntegrationsTest.php index 962c48e6d..bdd5cfa66 100644 --- a/tests/Unit/Integrations/IntegrationsTest.php +++ b/tests/Unit/Integrations/IntegrationsTest.php @@ -12,6 +12,7 @@ use Parsely\Integrations\Integration; use Parsely\Integrations\Integrations; use Parsely\Parsely; +use Parsely\Tests\Traits\TestsReflection; use ReflectionClass; use Yoast\WPTestUtils\BrainMonkey\TestCase; @@ -19,6 +20,8 @@ * Unit Tests for the Integrations collection. */ final class IntegrationsTest extends TestCase { + use TestsReflection; + /** * Internal variable. * @@ -49,7 +52,7 @@ public function test_an_integration_can_be_registered_to_a_new_Integrations_obje // Use Reflection to look inside the collection. $reflector = new ReflectionClass( $integrations ); $reflector_property = $reflector->getProperty( 'integrations' ); - $reflector_property->setAccessible( true ); + self::make_accessible( $reflector_property ); /** * Variable. * From b35ad839b04bb7f1c85d7c5a7814a7ed419ef193 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:26:07 +0200 Subject: [PATCH 08/31] Fix integration test errors on PHP 8.5 - Attempt 2 --- .../HeadlineTestingScriptsTest.php | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/tests/Integration/HeadlineTestingScriptsTest.php b/tests/Integration/HeadlineTestingScriptsTest.php index c38caf1e5..f6926736d 100644 --- a/tests/Integration/HeadlineTestingScriptsTest.php +++ b/tests/Integration/HeadlineTestingScriptsTest.php @@ -30,16 +30,6 @@ final class HeadlineTestingScriptsTest extends TestCase { */ private static $headline_testing; - /** - * One-line script string used in assertions. - * - * @since 3.21.0 - * - * @var string $one_line_script_string Holds the one-line script string. - */ - private static $one_line_script_string = 'src="https://experiments.parsely.com/vip-experiments.js?apiKey=demoaccount.parsely.com&ver=' - . PARSELY_VERSION . '" id="parsely-headline-testing-one-line-js"'; - /** * Advanced script string used in assertions. * @@ -262,7 +252,7 @@ public function test_markup_with_one_line_script_installation_method(): void { $output = (string) ob_get_clean(); // Markup should contain the one-line script and not the advanced script. - self::assertStringContainsString( self::$one_line_script_string, $output ); + $this->assert_one_line_script_in_output( $output ); self::assertStringNotContainsString( self::$advanced_script_string, $output ); } @@ -307,10 +297,7 @@ public function test_markup_with_one_line_script_and_additional_option(): void { $output = (string) ob_get_clean(); // Markup should contain the one-line script with the option's attribute. - self::assertStringContainsString( - self::$one_line_script_string . ' data-enable-live-updates="true"', - $output - ); + $this->assert_one_line_script_in_output( $output, array( 'data-enable-live-updates' => 'true' ) ); self::assertStringNotContainsString( self::$advanced_script_string, $output ); } @@ -410,7 +397,7 @@ public function test_markup_with_advanced_script_installation_method(): void { // Markup should contain the advanced script and not the one-line script. self::assertStringContainsString( self::$advanced_script_string, $output ); - self::assertStringNotContainsString( self::$one_line_script_string, $output ); + $this->assert_one_line_script_not_in_output( $output ); } /** @@ -460,7 +447,7 @@ public function test_markup_with_advanced_script_and_additional_option(): void { // Markup should contain the advanced script with the option's config. self::assertStringContainsString( self::$advanced_script_string, $output ); self::assertStringContainsString( 'enableLiveUpdates: true', $output ); - self::assertStringNotContainsString( self::$one_line_script_string, $output ); + $this->assert_one_line_script_not_in_output( $output ); } /** @@ -484,4 +471,42 @@ private function enable_headline_testing( array $settings = array() ): void { ) ); } + + /** + * Asserts that the one-line headline testing script tag is present in the + * given HTML output. + * + * Uses a regex with lookaheads to verify each attribute independently, + * making the assertion robust against WordPress changes to attribute order + * or HTML entity encoding variants (e.g. & vs &). + * + * @since 3.22.1 + * + * @param string $output The HTML output to search. + * @param array $extra_attrs Optional extra attributes to assert on the tag. + */ + private function assert_one_line_script_in_output( string $output, array $extra_attrs = array() ): void { + $version = preg_quote( PARSELY_VERSION, '~' ); + $lookaheads = '(?=[^>]*\bid="parsely-headline-testing-one-line-js")' + . '(?=[^>]*\bsrc="https://experiments\.parsely\.com/vip-experiments\.js' + . '\?apiKey=demoaccount\.parsely\.com(?:&|&)ver=' . $version . '")'; + + foreach ( $extra_attrs as $attr => $value ) { + $lookaheads .= '(?=[^>]*\b' . preg_quote( $attr, '~' ) . '="' . preg_quote( $value, '~' ) . '")'; + } + + self::assertMatchesRegularExpression( '~ Date: Wed, 4 Mar 2026 14:30:38 +0200 Subject: [PATCH 09/31] make_accessible(): Add since to DocBlock --- tests/Traits/TestsReflection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Traits/TestsReflection.php b/tests/Traits/TestsReflection.php index 845cf9436..7ef157128 100644 --- a/tests/Traits/TestsReflection.php +++ b/tests/Traits/TestsReflection.php @@ -20,6 +20,8 @@ trait TestsReflection { * 8.1, where setAccessible() is required. It is a no-op since PHP 8.1 * and deprecated since PHP 8.5. * + * @since 3.22.1 + * * @param ReflectionMethod|ReflectionProperty $reflection The reflection object. */ public static function make_accessible( object $reflection ): void { From dda13c3ccc02975cb45ba2f11468b02d1fc29458 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:52:26 +0200 Subject: [PATCH 10/31] Rebuild assets --- build/blocks/recommendations/edit.asset.php | 2 +- build/blocks/recommendations/edit.js | 2 +- build/blocks/recommendations/view.asset.php | 2 +- build/blocks/recommendations/view.js | 2 +- build/content-helper/dashboard-page.asset.php | 2 +- build/content-helper/dashboard-page.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/blocks/recommendations/edit.asset.php b/build/blocks/recommendations/edit.asset.php index 2edd8b9da..6616b2a27 100644 --- a/build/blocks/recommendations/edit.asset.php +++ b/build/blocks/recommendations/edit.asset.php @@ -1 +1 @@ - array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '11003228505bb09066c6'); + array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '747dde6c942b6f696e54'); diff --git a/build/blocks/recommendations/edit.js b/build/blocks/recommendations/edit.js index 96cbbecd6..18330547f 100644 --- a/build/blocks/recommendations/edit.js +++ b/build/blocks/recommendations/edit.js @@ -1 +1 @@ -!function(){"use strict";var e,n={271:function(e,n,r){var t,o,a=r(848),i=window.wp.blockEditor,l=window.wp.blocks,s=window.wp.i18n,c=window.wp.components,u=JSON.parse('{"UU":"wp-parsely/recommendations","uK":{"imagestyle":{"type":"string","default":"original"},"limit":{"type":"number","default":3},"openlinksinnewtab":{"type":"boolean","default":false},"showimages":{"type":"boolean","default":true},"sort":{"type":"string","default":"score"},"title":{"type":"string","default":"Related Content"}}}'),d=window.wp.element;(o=t||(t={}))[o.Error=0]="Error",o[o.Loaded=1]="Loaded",o[o.Recommendations=2]="Recommendations";var p=function(){return p=Object.assign||function(e){for(var n,r=1,t=arguments.length;r0&&o[o.length-1])||6!==l[0]&&2!==l[0])){a=0;continue}if(3===l[0]&&(!o||l[1]>o[0]&&l[1]=a)&&Object.keys(t.O).every((function(e){return t.O[e](r[s])}))?r.splice(s--,1):(l=!1,a0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[r,o,a]},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,{a:n}),n},t.d=function(e,n){for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},function(){var e={335:0,203:0};t.O.j=function(n){return 0===e[n]};var n=function(n,r){var o,a,i=r[0],l=r[1],s=r[2],c=0;if(i.some((function(n){return 0!==e[n]}))){for(o in l)t.o(l,o)&&(t.m[o]=l[o]);if(s)var u=s(t)}for(n&&n(r);c0&&o[o.length-1])||6!==l[0]&&2!==l[0])){a=0;continue}if(3===l[0]&&(!o||l[1]>o[0]&&l[1]=a)&&Object.keys(t.O).every((function(e){return t.O[e](r[s])}))?r.splice(s--,1):(l=!1,a0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[r,o,a]},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,{a:n}),n},t.d=function(e,n){for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},function(){var e={335:0,203:0};t.O.j=function(n){return 0===e[n]};var n=function(n,r){var o,a,i=r[0],l=r[1],s=r[2],c=0;if(i.some((function(n){return 0!==e[n]}))){for(o in l)t.o(l,o)&&(t.m[o]=l[o]);if(s)var u=s(t)}for(n&&n(r);c array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '075ef105cb061944f60c'); + array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => '1f46a0f1ce5b467874f8'); diff --git a/build/blocks/recommendations/view.js b/build/blocks/recommendations/view.js index aa6d411dd..97bad1081 100644 --- a/build/blocks/recommendations/view.js +++ b/build/blocks/recommendations/view.js @@ -1 +1 @@ -!function(){"use strict";var e={20:function(e,r,n){var t=n(609),o=Symbol.for("react.element"),a=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,s=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function c(e,r,n){var t,a={},c=null,u=null;for(t in void 0!==n&&(c=""+n),void 0!==r.key&&(c=""+r.key),void 0!==r.ref&&(u=r.ref),r)i.call(r,t)&&!l.hasOwnProperty(t)&&(a[t]=r[t]);if(e&&e.defaultProps)for(t in r=e.defaultProps)void 0===a[t]&&(a[t]=r[t]);return{$$typeof:o,type:e,key:c,ref:u,props:a,_owner:s.current}}r.Fragment=a,r.jsx=c,r.jsxs=c},848:function(e,r,n){e.exports=n(20)},609:function(e){e.exports=window.React}},r={};function n(t){var o=r[t];if(void 0!==o)return o.exports;var a=r[t]={exports:{}};return e[t](a,a.exports,n),a.exports}n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,{a:r}),r},n.d=function(e,r){for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)};var t,o,a=n(848),i=n(609),s=window.wp.domReady,l=n.n(s),c=window.wp.element,u=window.wp.i18n;(o=t||(t={}))[o.Error=0]="Error",o[o.Loaded=1]="Loaded",o[o.Recommendations=2]="Recommendations";var d=function(){return d=Object.assign||function(e){for(var r,n=1,t=arguments.length;n0&&o[o.length-1])||6!==s[0]&&2!==s[0])){a=0;continue}if(3===s[0]&&(!o||s[1]>o[0]&&s[1]0&&o[o.length-1])||6!==s[0]&&2!==s[0])){a=0;continue}if(3===s[0]&&(!o||s[1]>o[0]&&s[1] array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '13eedf9919b777db35ac'); + array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-url'), 'version' => '89926571b1fa95966f9f'); diff --git a/build/content-helper/dashboard-page.js b/build/content-helper/dashboard-page.js index 310dd4f89..b57978875 100644 --- a/build/content-helper/dashboard-page.js +++ b/build/content-helper/dashboard-page.js @@ -1,4 +1,4 @@ -!function(){"use strict";var e,t,n={20:function(e,t,n){var r=n(609),o=Symbol.for("react.element"),i=Symbol.for("react.fragment"),a=Object.prototype.hasOwnProperty,s=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function c(e,t,n){var r,i={},c=null,u=null;for(r in void 0!==n&&(c=""+n),void 0!==t.key&&(c=""+t.key),void 0!==t.ref&&(u=t.ref),t)a.call(t,r)&&!l.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:o,type:e,key:c,ref:u,props:i,_owner:s.current}}t.Fragment=i,t.jsx=c,t.jsxs=c},848:function(e,t,n){e.exports=n(20)},609:function(e){e.exports=window.React}},r={};function o(e){var t=r[e];if(void 0!==t)return t.exports;var i=r[e]={exports:{}};return n[e](i,i.exports,o),i.exports}o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,{a:t}),t},t=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},o.t=function(n,r){if(1&r&&(n=this(n)),8&r)return n;if("object"==typeof n&&n){if(4&r&&n.__esModule)return n;if(16&r&&"function"==typeof n.then)return n}var i=Object.create(null);o.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var s=2&r&&n;"object"==typeof s&&!~e.indexOf(s);s=t(s))Object.getOwnPropertyNames(s).forEach((function(e){a[e]=function(){return n[e]}}));return a.default=function(){return n},o.d(i,a),i},o.d=function(e,t){for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e=o(848),t=o(609),n=o.t(t,2),r="popstate";function i(e={}){return function(e,t,n,o={}){let{window:i=document.defaultView,v5Compat:s=!1}=o,d=i.history,p="POP",f=null,h=g();function g(){return(d.state||{idx:null}).idx}function v(){p="POP";let e=g(),t=null==e?null:e-h;h=e,f&&f({action:p,location:y.location,delta:t})}function m(e){return function(e,t=!1){let n="http://localhost";"undefined"!=typeof window&&(n="null"!==window.location.origin?window.location.origin:window.location.href),a(n,"No window.location.(origin|href) available to create URL");let r="string"==typeof e?e:u(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}(e)}null==h&&(h=0,d.replaceState({...d.state,idx:h},""));let y={get action(){return p},get location(){return e(i,d)},listen(e){if(f)throw new Error("A history only accepts one active listener");return i.addEventListener(r,v),f=e,()=>{i.removeEventListener(r,v),f=null}},createHref(e){return t(i,e)},createURL:m,encodeLocation(e){let t=m(e);return{pathname:t.pathname,search:t.search,hash:t.hash}},push:function(e,t){p="PUSH";let r=c(y.location,e,t);n&&n(r,e),h=g()+1;let o=l(r,h),a=y.createHref(r);try{d.pushState(o,"",a)}catch(e){if(e instanceof DOMException&&"DataCloneError"===e.name)throw e;i.location.assign(a)}s&&f&&f({action:p,location:y.location,delta:1})},replace:function(e,t){p="REPLACE";let r=c(y.location,e,t);n&&n(r,e),h=g();let o=l(r,h),i=y.createHref(r);d.replaceState(o,"",i),s&&f&&f({action:p,location:y.location,delta:0})},go(e){return d.go(e)}};return y}((function(e,t){let{pathname:n="/",search:r="",hash:o=""}=d(e.location.hash.substring(1));return n.startsWith("/")||n.startsWith(".")||(n="/"+n),c("",{pathname:n,search:r,hash:o},t.state&&t.state.usr||null,t.state&&t.state.key||"default")}),(function(e,t){let n=e.document.querySelector("base"),r="";if(n&&n.getAttribute("href")){let t=e.location.href,n=t.indexOf("#");r=-1===n?t:t.slice(0,n)}return r+"#"+("string"==typeof t?t:u(t))}),(function(e,t){s("/"===e.pathname.charAt(0),`relative pathnames are not supported in hash history.push(${JSON.stringify(t)})`)}),e)}function a(e,t){if(!1===e||null==e)throw new Error(t)}function s(e,t){if(!e){"undefined"!=typeof console&&console.warn(t);try{throw new Error(t)}catch(e){}}}function l(e,t){return{usr:e.state,key:e.key,idx:t}}function c(e,t,n=null,r){return{pathname:"string"==typeof e?e:e.pathname,search:"",hash:"",..."string"==typeof t?d(t):t,state:n,key:t&&t.key||r||Math.random().toString(36).substring(2,10)}}function u({pathname:e="/",search:t="",hash:n=""}){return t&&"?"!==t&&(e+="?"===t.charAt(0)?t:"?"+t),n&&"#"!==n&&(e+="#"===n.charAt(0)?n:"#"+n),e}function d(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function p(e,t,n="/"){return function(e,t,n,r){let o=L(("string"==typeof t?d(t):t).pathname||"/",n);if(null==o)return null;let i=f(e);!function(e){e.sort(((e,t)=>e.score!==t.score?t.score-e.score:function(e,t){return e.length===t.length&&e.slice(0,-1).every(((e,n)=>e===t[n]))?e[e.length-1]-t[t.length-1]:0}(e.routesMeta.map((e=>e.childrenIndex)),t.routesMeta.map((e=>e.childrenIndex)))))}(i);let a=null;for(let e=0;null==a&&e{let c={relativePath:void 0===l?e.path||"":l,caseSensitive:!0===e.caseSensitive,childrenIndex:i,route:e};if(c.relativePath.startsWith("/")){if(!c.relativePath.startsWith(r)&&s)return;a(c.relativePath.startsWith(r),`Absolute route path "${c.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),c.relativePath=c.relativePath.slice(r.length)}let u=R([r,c.relativePath]),d=n.concat(c);e.children&&e.children.length>0&&(a(!0!==e.index,`Index routes must not have child routes. Please remove all child routes from route path "${u}".`),f(e.children,t,d,u,s)),(null!=e.path||e.index)&&t.push({path:u,score:_(u,e.index),routesMeta:d})};return e.forEach(((e,t)=>{if(""!==e.path&&e.path?.includes("?"))for(let n of h(e.path))i(e,t,!0,n);else i(e,t)})),t}function h(e){let t=e.split("/");if(0===t.length)return[];let[n,...r]=t,o=n.endsWith("?"),i=n.replace(/\?$/,"");if(0===r.length)return o?[i,""]:[i];let a=h(r.join("/")),s=[];return s.push(...a.map((e=>""===e?i:[i,e].join("/")))),o&&s.push(...a),s.map((t=>e.startsWith("/")&&""===t?"/":t))}new WeakMap;var g=/^:[\w-]+$/,v=3,m=2,y=1,b=10,w=-2,x=e=>"*"===e;function _(e,t){let n=e.split("/"),r=n.length;return n.some(x)&&(r+=w),t&&(r+=m),n.filter((e=>!x(e))).reduce(((e,t)=>e+(g.test(t)?v:""===t?y:b)),r)}function k(e,t,n=!1){let{routesMeta:r}=e,o={},i="/",a=[];for(let e=0;e(r.push({paramName:t,isOptional:null!=n}),n?"/?([^\\/]+)?":"/([^\\/]+)"))).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return e.endsWith("*")?(r.push({paramName:"*"}),o+="*"===e||"/*"===e?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?o+="\\/*$":""!==e&&"/"!==e&&(o+="(?:(?=\\/|$))"),[new RegExp(o,t?void 0:"i"),r]}(e.path,e.caseSensitive,e.end),o=t.match(n);if(!o)return null;let i=o[0],a=i.replace(/(.)\/+$/,"$1"),l=o.slice(1);return{params:r.reduce(((e,{paramName:t,isOptional:n},r)=>{if("*"===t){let e=l[r]||"";a=i.slice(0,i.length-e.length).replace(/(.)\/+$/,"$1")}const o=l[r];return e[t]=n&&!o?void 0:(o||"").replace(/%2F/g,"/"),e}),{}),pathname:i,pathnameBase:a,pattern:e}}function E(e){try{return e.split("/").map((e=>decodeURIComponent(e).replace(/\//g,"%2F"))).join("/")}catch(t){return s(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function L(e,t){if("/"===t)return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&"/"!==r?null:e.slice(n)||"/"}var P=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function T(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach((e=>{".."===e?n.length>1&&n.pop():"."!==e&&n.push(e)})),n.length>1?n.join("/"):"/"}function j(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function C(e){let t=function(e){return e.filter(((e,t)=>0===t||e.route.path&&e.route.path.length>0))}(e);return t.map(((e,n)=>n===t.length-1?e.pathname:e.pathnameBase))}function N(e,t,n,r=!1){let o;"string"==typeof e?o=d(e):(o={...e},a(!o.pathname||!o.pathname.includes("?"),j("?","pathname","search",o)),a(!o.pathname||!o.pathname.includes("#"),j("#","pathname","hash",o)),a(!o.search||!o.search.includes("#"),j("#","search","hash",o)));let i,l=""===e||""===o.pathname,c=l?"/":o.pathname;if(null==c)i=n;else{let e=t.length-1;if(!r&&c.startsWith("..")){let t=c.split("/");for(;".."===t[0];)t.shift(),e-=1;o.pathname=t.join("/")}i=e>=0?t[e]:"/"}let u=function(e,t="/"){let n,{pathname:r,search:o="",hash:i=""}="string"==typeof e?d(e):e;if(r)if(a=r,P.test(a))n=r;else{if(r.includes("//")){let e=r;r=r.replace(/\/\/+/g,"/"),s(!1,`Pathnames cannot have embedded double slashes - normalizing ${e} -> ${r}`)}n=r.startsWith("/")?T(r.substring(1),"/"):T(r,t)}else n=t;var a;return{pathname:n,search:A(o),hash:O(i)}}(o,i),p=c&&"/"!==c&&c.endsWith("/"),f=(l||"."===c)&&n.endsWith("/");return u.pathname.endsWith("/")||!p&&!f||(u.pathname+="/"),u}var R=e=>e.join("/").replace(/\/\/+/g,"/"),I=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),A=e=>e&&"?"!==e?e.startsWith("?")?e:"?"+e:"",O=e=>e&&"#"!==e?e.startsWith("#")?e:"#"+e:"",D=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||"",this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function B(e){return null!=e&&"number"==typeof e.status&&"string"==typeof e.statusText&&"boolean"==typeof e.internal&&"data"in e}function M(e){return e.map((e=>e.route.path)).filter(Boolean).join("/").replace(/\/\/*/g,"/")||"/"}var G="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement;function U(e,t){let n=e;if("string"!=typeof n||!P.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,o=!1;if(G)try{let e=new URL(window.location.href),r=n.startsWith("//")?new URL(e.protocol+n):new URL(n),i=L(r.pathname,t);r.origin===e.origin&&null!=i?n=i+r.search+r.hash:o=!0}catch(e){s(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:o,to:n}}Symbol("Uninstrumented"),Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var F=["POST","PUT","PATCH","DELETE"],H=(new Set(F),["GET",...F]);new Set(H),Symbol("ResetLoaderData");var V=t.createContext(null);V.displayName="DataRouter";var $=t.createContext(null);$.displayName="DataRouterState";var W=t.createContext(!1);var z=t.createContext({isTransitioning:!1});z.displayName="ViewTransition",t.createContext(new Map).displayName="Fetchers",t.createContext(null).displayName="Await";var q=t.createContext(null);q.displayName="Navigation";var Z=t.createContext(null);Z.displayName="Location";var K=t.createContext({outlet:null,matches:[],isDataRoute:!1});K.displayName="Route";var Y=t.createContext(null);Y.displayName="RouteError";var J="REACT_ROUTER_ERROR";function X(){return null!=t.useContext(Z)}function Q(){return a(X(),"useLocation() may be used only in the context of a component."),t.useContext(Z).location}var ee="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function te(e){t.useContext(q).static||t.useLayoutEffect(e)}function ne(){let{isDataRoute:e}=t.useContext(K);return e?function(){let{router:e}=function(e){let n=t.useContext(V);return a(n,pe(e)),n}("useNavigate"),n=fe("useNavigate"),r=t.useRef(!1);return te((()=>{r.current=!0})),t.useCallback((async(t,o={})=>{s(r.current,ee),r.current&&("number"==typeof t?await e.navigate(t):await e.navigate(t,{fromRouteId:n,...o}))}),[e,n])}():function(){a(X(),"useNavigate() may be used only in the context of a component.");let e=t.useContext(V),{basename:n,navigator:r}=t.useContext(q),{matches:o}=t.useContext(K),{pathname:i}=Q(),l=JSON.stringify(C(o)),c=t.useRef(!1);return te((()=>{c.current=!0})),t.useCallback(((t,o={})=>{if(s(c.current,ee),!c.current)return;if("number"==typeof t)return void r.go(t);let a=N(t,JSON.parse(l),i,"path"===o.relative);null==e&&"/"!==n&&(a.pathname="/"===a.pathname?n:R([n,a.pathname])),(o.replace?r.replace:r.push)(a,o.state,o)}),[n,r,l,i,e])}()}function re(){let{matches:e}=t.useContext(K),n=e[e.length-1];return n?n.params:{}}function oe(e,{relative:n}={}){let{matches:r}=t.useContext(K),{pathname:o}=Q(),i=JSON.stringify(C(r));return t.useMemo((()=>N(e,JSON.parse(i),o,"path"===n)),[e,i,o,n])}function ie(e,n,r,o,i){a(X(),"useRoutes() may be used only in the context of a component.");let{navigator:l}=t.useContext(q),{matches:c}=t.useContext(K),u=c[c.length-1],f=u?u.params:{},h=u?u.pathname:"/",g=u?u.pathnameBase:"/",v=u&&u.route;{let e=v&&v.path||"";ge(h,!v||e.endsWith("*")||e.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${h}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.\n\nPlease change the parent to .`)}let m,y=Q();if(n){let e="string"==typeof n?d(n):n;a("/"===g||e.pathname?.startsWith(g),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${g}" but pathname "${e.pathname}" was given in the \`location\` prop.`),m=e}else m=y;let b=m.pathname||"/",w=b;if("/"!==g){let e=g.replace(/^\//,"").split("/");w="/"+b.replace(/^\//,"").split("/").slice(e.length).join("/")}let x=p(e,{pathname:w});s(v||null!=x,`No routes matched location "${m.pathname}${m.search}${m.hash}" `),s(null==x||void 0!==x[x.length-1].route.element||void 0!==x[x.length-1].route.Component||void 0!==x[x.length-1].route.lazy,`Matched leaf route at location "${m.pathname}${m.search}${m.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let _=function(e,n=[],r=null,o=null){if(null==e){if(!r)return null;if(r.errors)e=r.matches;else{if(0!==n.length||r.initialized||!(r.matches.length>0))return null;e=r.matches}}let i=e,s=r?.errors;if(null!=s){let e=i.findIndex((e=>e.route.id&&void 0!==s?.[e.route.id]));a(e>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(s).join(",")}`),i=i.slice(0,Math.min(i.length,e+1))}let l=!1,c=-1;if(r)for(let e=0;e=0?i.slice(0,c+1):[i[0]];break}}}let u=r&&o?(e,t)=>{o(e,{location:r.location,params:r.matches?.[0]?.params??{},unstable_pattern:M(r.matches),errorInfo:t})}:void 0;return i.reduceRight(((e,o,a)=>{let d,p=!1,f=null,h=null;r&&(d=s&&o.route.id?s[o.route.id]:void 0,f=o.route.errorElement||se,l&&(c<0&&0===a?(ge("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),p=!0,h=null):c===a&&(p=!0,h=o.route.hydrateFallbackElement||null)));let g=n.concat(i.slice(0,a+1)),v=()=>{let n;return n=d?f:p?h:o.route.Component?t.createElement(o.route.Component,null):o.route.element?o.route.element:e,t.createElement(de,{match:o,routeContext:{outlet:e,matches:g,isDataRoute:null!=r},children:n})};return r&&(o.route.ErrorBoundary||o.route.errorElement||0===a)?t.createElement(le,{location:r.location,revalidation:r.revalidation,component:f,error:d,children:v(),routeContext:{outlet:null,matches:g,isDataRoute:!0},onError:u}):v()}),null)}(x&&x.map((e=>Object.assign({},e,{params:Object.assign({},f,e.params),pathname:R([g,l.encodeLocation?l.encodeLocation(e.pathname.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:e.pathname]),pathnameBase:"/"===e.pathnameBase?g:R([g,l.encodeLocation?l.encodeLocation(e.pathnameBase.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:e.pathnameBase])}))),c,r,o,i);return n&&_?t.createElement(Z.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...m},navigationType:"POP"}},_):_}function ae(){let e=function(){let e=t.useContext(Y),n=function(e){let n=t.useContext($);return a(n,pe(e)),n}("useRouteError"),r=fe("useRouteError");return void 0!==e?e:n.errors?.[r]}(),n=B(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),r=e instanceof Error?e.stack:null,o="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:o},s={padding:"2px 4px",backgroundColor:o},l=null;return console.error("Error handled by React Router default ErrorBoundary:",e),l=t.createElement(t.Fragment,null,t.createElement("p",null,"💿 Hey developer 👋"),t.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",t.createElement("code",{style:s},"ErrorBoundary")," or"," ",t.createElement("code",{style:s},"errorElement")," prop on your route.")),t.createElement(t.Fragment,null,t.createElement("h2",null,"Unexpected Application Error!"),t.createElement("h3",{style:{fontStyle:"italic"}},n),r?t.createElement("pre",{style:i},r):null,l)}t.createContext(null);var se=t.createElement(ae,null),le=class extends t.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||"idle"!==t.revalidation&&"idle"===e.revalidation?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:void 0!==e.error?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&"object"==typeof e&&e&&"digest"in e&&"string"==typeof e.digest){const t=function(e){if(e.startsWith(`${J}:ROUTE_ERROR_RESPONSE:{`))try{let t=JSON.parse(e.slice(40));if("object"==typeof t&&t&&"number"==typeof t.status&&"string"==typeof t.statusText)return new D(t.status,t.statusText,t.data)}catch{}}(e.digest);t&&(e=t)}let n=void 0!==e?t.createElement(K.Provider,{value:this.props.routeContext},t.createElement(Y.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?t.createElement(ue,{error:e},n):n}};le.contextType=W;var ce=new WeakMap;function ue({children:e,error:n}){let{basename:r}=t.useContext(q);if("object"==typeof n&&n&&"digest"in n&&"string"==typeof n.digest){let e=function(e){if(e.startsWith(`${J}:REDIRECT:{`))try{let t=JSON.parse(e.slice(28));if("object"==typeof t&&t&&"number"==typeof t.status&&"string"==typeof t.statusText&&"string"==typeof t.location&&"boolean"==typeof t.reloadDocument&&"boolean"==typeof t.replace)return t}catch{}}(n.digest);if(e){let o=ce.get(n);if(o)throw o;let i=U(e.location,r);if(G&&!ce.get(n)){if(!i.isExternal&&!e.reloadDocument){const t=Promise.resolve().then((()=>window.__reactRouterDataRouter.navigate(i.to,{replace:e.replace})));throw ce.set(n,t),t}window.location.href=i.absoluteURL||i.to}return t.createElement("meta",{httpEquiv:"refresh",content:`0;url=${i.absoluteURL||i.to}`})}}return e}function de({routeContext:e,match:n,children:r}){let o=t.useContext(V);return o&&o.static&&o.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=n.route.id),t.createElement(K.Provider,{value:e},r)}function pe(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function fe(e){let n=function(e){let n=t.useContext(K);return a(n,pe(e)),n}(e),r=n.matches[n.matches.length-1];return a(r.route.id,`${e} can only be used on routes that contain a unique "id"`),r.route.id}var he={};function ge(e,t,n){t||he[e]||(he[e]=!0,s(!1,n))}function ve({to:e,replace:n,state:r,relative:o}){a(X()," may be used only in the context of a component.");let{static:i}=t.useContext(q);s(!i," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:l}=t.useContext(K),{pathname:c}=Q(),u=ne(),d=N(e,C(l),c,"path"===o),p=JSON.stringify(d);return t.useEffect((()=>{u(JSON.parse(p),{replace:n,state:r,relative:o})}),[u,p,o,n,r]),null}function me(e){a(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function ye({basename:e="/",children:n=null,location:r,navigationType:o="POP",navigator:i,static:l=!1,unstable_useTransitions:c}){a(!X(),"You cannot render a inside another . You should never have more than one in your app.");let u=e.replace(/^\/*/,"/"),p=t.useMemo((()=>({basename:u,navigator:i,static:l,unstable_useTransitions:c,future:{}})),[u,i,l,c]);"string"==typeof r&&(r=d(r));let{pathname:f="/",search:h="",hash:g="",state:v=null,key:m="default"}=r,y=t.useMemo((()=>{let e=L(f,u);return null==e?null:{location:{pathname:e,search:h,hash:g,state:v,key:m},navigationType:o}}),[u,f,h,g,v,m,o]);return s(null!=y,` is not able to match the URL "${f}${h}${g}" because it does not start with the basename, so the won't render anything.`),null==y?null:t.createElement(q.Provider,{value:p},t.createElement(Z.Provider,{children:n,value:y}))}function be({children:e,location:t}){return ie(we(e),t)}function we(e,n=[]){let r=[];return t.Children.forEach(e,((e,o)=>{if(!t.isValidElement(e))return;let i=[...n,o];if(e.type===t.Fragment)return void r.push.apply(r,we(e.props.children,i));a(e.type===me,`[${"string"==typeof e.type?e.type:e.type.name}] is not a component. All component children of must be a or `),a(!e.props.index||!e.props.children,"An index route cannot have child routes.");let s={id:e.props.id||i.join("-"),caseSensitive:e.props.caseSensitive,element:e.props.element,Component:e.props.Component,index:e.props.index,path:e.props.path,middleware:e.props.middleware,loader:e.props.loader,action:e.props.action,hydrateFallbackElement:e.props.hydrateFallbackElement,HydrateFallback:e.props.HydrateFallback,errorElement:e.props.errorElement,ErrorBoundary:e.props.ErrorBoundary,hasErrorBoundary:!0===e.props.hasErrorBoundary||null!=e.props.ErrorBoundary||null!=e.props.errorElement,shouldRevalidate:e.props.shouldRevalidate,handle:e.props.handle,lazy:e.props.lazy};e.props.children&&(s.children=we(e.props.children,i)),r.push(s)})),r}n.useOptimistic,t.memo((function({routes:e,future:t,state:n,onError:r}){return ie(e,void 0,n,r,t)})),t.Component;var xe="get",_e="application/x-www-form-urlencoded";function ke(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement}var Se=null,Ee=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Le(e){return null==e||Ee.has(e)?e:(s(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${_e}"`),null)}function Pe(e,t){if(!1===e||null==e)throw new Error(t)}function Te(e){return null!=e&&(null==e.href?"preload"===e.rel&&"string"==typeof e.imageSrcSet&&"string"==typeof e.imageSizes:"string"==typeof e.rel&&"string"==typeof e.href)}function je(e,t,n,r,o,i){let a=(e,t)=>!n[t]||e.route.id!==n[t].route.id,s=(e,t)=>n[t].pathname!==e.pathname||n[t].route.path?.endsWith("*")&&n[t].params["*"]!==e.params["*"];return"assets"===i?t.filter(((e,t)=>a(e,t)||s(e,t))):"data"===i?t.filter(((t,i)=>{let l=r.routes[t.route.id];if(!l||!l.hasLoader)return!1;if(a(t,i)||s(t,i))return!0;if(t.route.shouldRevalidate){let r=t.route.shouldRevalidate({currentUrl:new URL(o.pathname+o.search+o.hash,window.origin),currentParams:n[0]?.params||{},nextUrl:new URL(e,window.origin),nextParams:t.params,defaultShouldRevalidate:!0});if("boolean"==typeof r)return r}return!0})):[]}function Ce(e,t,{includeHydrateFallback:n}={}){return r=e.map((e=>{let r=t.routes[e.route.id];if(!r)return[];let o=[r.module];return r.clientActionModule&&(o=o.concat(r.clientActionModule)),r.clientLoaderModule&&(o=o.concat(r.clientLoaderModule)),n&&r.hydrateFallbackModule&&(o=o.concat(r.hydrateFallbackModule)),r.imports&&(o=o.concat(r.imports)),o})).flat(1),[...new Set(r)];var r}function Ne(){let e=t.useContext(V);return Pe(e,"You must render this element inside a element"),e}function Re(){let e=t.useContext($);return Pe(e,"You must render this element inside a element"),e}Object.getOwnPropertyNames(Object.prototype).sort().join("\0"),"undefined"!=typeof window?window:"undefined"!=typeof globalThis&&globalThis,Symbol("SingleFetchRedirect");var Ie=t.createContext(void 0);function Ae(){let e=t.useContext(Ie);return Pe(e,"You must render this element inside a element"),e}function Oe(e,t){return n=>{e&&e(n),n.defaultPrevented||t(n)}}function De({page:e,...n}){let{router:r}=Ne(),o=t.useMemo((()=>p(r.routes,e,r.basename)),[r.routes,e,r.basename]);return o?t.createElement(Me,{page:e,matches:o,...n}):null}function Be(e){let{manifest:n,routeModules:r}=Ae(),[o,i]=t.useState([]);return t.useEffect((()=>{let t=!1;return async function(e,t,n){return function(e,t){let n=new Set,r=new Set(t);return e.reduce(((e,o)=>{if(t&&(null==(i=o)||"string"!=typeof i.page)&&"script"===o.as&&o.href&&r.has(o.href))return e;var i;let a=JSON.stringify(function(e){let t={},n=Object.keys(e).sort();for(let r of n)t[r]=e[r];return t}(o));return n.has(a)||(n.add(a),e.push({key:a,link:o})),e}),[])}((await Promise.all(e.map((async e=>{let r=t.routes[e.route.id];if(r){let e=await async function(e,t){if(e.id in t)return t[e.id];try{let n=await import(e.module);return t[e.id]=n,n}catch(t){return console.error(`Error loading route module \`${e.module}\`, reloading page...`),console.error(t),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise((()=>{}))}}(r,n);return e.links?e.links():[]}return[]})))).flat(1).filter(Te).filter((e=>"stylesheet"===e.rel||"preload"===e.rel)).map((e=>"stylesheet"===e.rel?{...e,rel:"prefetch",as:"style"}:{...e,rel:"prefetch"})))}(e,n,r).then((e=>{t||i(e)})),()=>{t=!0}}),[e,n,r]),o}function Me({page:e,matches:n,...r}){let o=Q(),{future:i,manifest:a,routeModules:s}=Ae(),{basename:l}=Ne(),{loaderData:c,matches:u}=Re(),d=t.useMemo((()=>je(e,n,u,a,o,"data")),[e,n,u,a,o]),p=t.useMemo((()=>je(e,n,u,a,o,"assets")),[e,n,u,a,o]),f=t.useMemo((()=>{if(e===o.pathname+o.search+o.hash)return[];let t=new Set,r=!1;if(n.forEach((e=>{let n=a.routes[e.route.id];n&&n.hasLoader&&(!d.some((t=>t.route.id===e.route.id))&&e.route.id in c&&s[e.route.id]?.shouldRevalidate||n.hasClientLoader?r=!0:t.add(e.route.id))})),0===t.size)return[];let u=function(e,t,n,r){let o="string"==typeof e?new URL(e,"undefined"==typeof window?"server://singlefetch/":window.location.origin):e;return n?o.pathname.endsWith("/")?o.pathname=`${o.pathname}_.${r}`:o.pathname=`${o.pathname}.${r}`:"/"===o.pathname?o.pathname=`_root.${r}`:t&&"/"===L(o.pathname,t)?o.pathname=`${t.replace(/\/$/,"")}/_root.${r}`:o.pathname=`${o.pathname.replace(/\/$/,"")}.${r}`,o}(e,l,i.unstable_trailingSlashAwareDataRequests,"data");return r&&t.size>0&&u.searchParams.set("_routes",n.filter((e=>t.has(e.route.id))).map((e=>e.route.id)).join(",")),[u.pathname+u.search]}),[l,i.unstable_trailingSlashAwareDataRequests,c,o,a,d,n,e,s]),h=t.useMemo((()=>Ce(p,a)),[p,a]),g=Be(p);return t.createElement(t.Fragment,null,f.map((e=>t.createElement("link",{key:e,rel:"prefetch",as:"fetch",href:e,...r}))),h.map((e=>t.createElement("link",{key:e,rel:"modulepreload",href:e,...r}))),g.map((({key:e,link:n})=>t.createElement("link",{key:e,nonce:r.nonce,...n}))))}Ie.displayName="FrameworkContext";function Ge(...e){return t=>{e.forEach((e=>{"function"==typeof e?e(t):null!=e&&(e.current=t)}))}}t.Component;var Ue="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement;try{Ue&&(window.__reactRouterVersion="7.12.0")}catch(e){}function Fe({basename:e,children:n,unstable_useTransitions:r,window:o}){let a=t.useRef();null==a.current&&(a.current=i({window:o,v5Compat:!0}));let s=a.current,[l,c]=t.useState({action:s.action,location:s.location}),u=t.useCallback((e=>{!1===r?c(e):t.startTransition((()=>c(e)))}),[r]);return t.useLayoutEffect((()=>s.listen(u)),[s,u]),t.createElement(ye,{basename:e,children:n,location:l.location,navigationType:l.action,navigator:s,unstable_useTransitions:r})}var He=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Ve=t.forwardRef((function({onClick:e,discover:n="render",prefetch:r="none",relative:o,reloadDocument:i,replace:s,state:l,target:c,to:d,preventScrollReset:p,viewTransition:f,unstable_defaultShouldRevalidate:h,...g},v){let{basename:m,unstable_useTransitions:y}=t.useContext(q),b="string"==typeof d&&He.test(d),w=U(d,m),x=function(e,{relative:n}={}){a(X(),"useHref() may be used only in the context of a component.");let{basename:r,navigator:o}=t.useContext(q),{hash:i,pathname:s,search:l}=oe(e,{relative:n}),c=s;return"/"!==r&&(c="/"===s?r:R([r,s])),o.createHref({pathname:c,search:l,hash:i})}(d=w.to,{relative:o}),[_,k,S]=function(e,n){let r=t.useContext(Ie),[o,i]=t.useState(!1),[a,s]=t.useState(!1),{onFocus:l,onBlur:c,onMouseEnter:u,onMouseLeave:d,onTouchStart:p}=n,f=t.useRef(null);t.useEffect((()=>{if("render"===e&&s(!0),"viewport"===e){let e=new IntersectionObserver((e=>{e.forEach((e=>{s(e.isIntersecting)}))}),{threshold:.5});return f.current&&e.observe(f.current),()=>{e.disconnect()}}}),[e]),t.useEffect((()=>{if(o){let e=setTimeout((()=>{s(!0)}),100);return()=>{clearTimeout(e)}}}),[o]);let h=()=>{i(!0)},g=()=>{i(!1),s(!1)};return r?"intent"!==e?[a,f,{}]:[a,f,{onFocus:Oe(l,h),onBlur:Oe(c,g),onMouseEnter:Oe(u,h),onMouseLeave:Oe(d,g),onTouchStart:Oe(p,h)}]:[!1,f,{}]}(r,g),E=function(e,{target:n,replace:r,state:o,preventScrollReset:i,relative:a,viewTransition:s,unstable_defaultShouldRevalidate:l,unstable_useTransitions:c}={}){let d=ne(),p=Q(),f=oe(e,{relative:a});return t.useCallback((h=>{if(function(e,t){return!(0!==e.button||t&&"_self"!==t||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e))}(h,n)){h.preventDefault();let n=void 0!==r?r:u(p)===u(f),g=()=>d(e,{replace:n,state:o,preventScrollReset:i,relative:a,viewTransition:s,unstable_defaultShouldRevalidate:l});c?t.startTransition((()=>g())):g()}}),[p,d,f,r,o,n,e,i,a,s,l,c])}(d,{replace:s,state:l,target:c,preventScrollReset:p,relative:o,viewTransition:f,unstable_defaultShouldRevalidate:h,unstable_useTransitions:y}),L=t.createElement("a",{...g,...S,href:w.absoluteURL||x,onClick:w.isExternal||i?e:function(t){e&&e(t),t.defaultPrevented||E(t)},ref:Ge(v,k),target:c,"data-discover":b||"render"!==n?void 0:"true"});return _&&!b?t.createElement(t.Fragment,null,L,t.createElement(De,{page:x})):L}));function $e(e){let n=t.useContext(V);return a(n,function(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}(e)),n}Ve.displayName="Link",t.forwardRef((function({"aria-current":e="page",caseSensitive:n=!1,className:r="",end:o=!1,style:i,to:s,viewTransition:l,children:c,...u},d){let p=oe(s,{relative:u.relative}),f=Q(),h=t.useContext($),{navigator:g,basename:v}=t.useContext(q),m=null!=h&&function(e,{relative:n}={}){let r=t.useContext(z);a(null!=r,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:o}=$e("useViewTransitionState"),i=oe(e,{relative:n});if(!r.isTransitioning)return!1;let s=L(r.currentLocation.pathname,o)||r.currentLocation.pathname,l=L(r.nextLocation.pathname,o)||r.nextLocation.pathname;return null!=S(i.pathname,l)||null!=S(i.pathname,s)}(p)&&!0===l,y=g.encodeLocation?g.encodeLocation(p).pathname:p.pathname,b=f.pathname,w=h&&h.navigation&&h.navigation.location?h.navigation.location.pathname:null;n||(b=b.toLowerCase(),w=w?w.toLowerCase():null,y=y.toLowerCase()),w&&v&&(w=L(w,v)||w);const x="/"!==y&&y.endsWith("/")?y.length-1:y.length;let _,k=b===y||!o&&b.startsWith(y)&&"/"===b.charAt(x),E=null!=w&&(w===y||!o&&w.startsWith(y)&&"/"===w.charAt(y.length)),P={isActive:k,isPending:E,isTransitioning:m},T=k?e:void 0;_="function"==typeof r?r(P):[r,k?"active":null,E?"pending":null,m?"transitioning":null].filter(Boolean).join(" ");let j="function"==typeof i?i(P):i;return t.createElement(Ve,{...u,"aria-current":T,className:_,ref:d,style:j,to:s,viewTransition:l},"function"==typeof c?c(P):c)})).displayName="NavLink",t.forwardRef((({discover:e="render",fetcherKey:n,navigate:r,reloadDocument:o,replace:i,state:s,method:l=xe,action:c,onSubmit:d,relative:p,preventScrollReset:f,viewTransition:h,unstable_defaultShouldRevalidate:g,...v},m)=>{let{unstable_useTransitions:y}=t.useContext(q),b=function(){let{router:e}=$e("useSubmit"),{basename:n}=t.useContext(q),r=fe("useRouteId"),o=e.fetch,i=e.navigate;return t.useCallback((async(e,t={})=>{let{action:a,method:s,encType:l,formData:c,body:u}=function(e,t){let n,r,o,i,a;if(ke(s=e)&&"form"===s.tagName.toLowerCase()){let a=e.getAttribute("action");r=a?L(a,t):null,n=e.getAttribute("method")||xe,o=Le(e.getAttribute("enctype"))||_e,i=new FormData(e)}else if(function(e){return ke(e)&&"button"===e.tagName.toLowerCase()}(e)||function(e){return ke(e)&&"input"===e.tagName.toLowerCase()}(e)&&("submit"===e.type||"image"===e.type)){let a=e.form;if(null==a)throw new Error('Cannot submit a - } + + + + { postId > 0 && isPostTrackable && permissions.TrafficBoost && + + } + ); }; From b552451aab75d35a66fd49750b6f3b254572c414 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:19:46 +0200 Subject: [PATCH 24/31] Fix tests to handle dynamic siteurl for subdirectory installations --- tests/Integration/UI/SettingsPageTest.php | 15 ++++-- tests/Integration/UI/SiteHealthTest.php | 59 ++++++++++++----------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/tests/Integration/UI/SettingsPageTest.php b/tests/Integration/UI/SettingsPageTest.php index eb911e324..f07868677 100644 --- a/tests/Integration/UI/SettingsPageTest.php +++ b/tests/Integration/UI/SettingsPageTest.php @@ -600,13 +600,18 @@ public function test_get_settings_url_with_and_without_blog_id(): void { * @covers \Parsely\Parsely::get_settings_url */ public function test_get_settings_url_with_subdirectory_install(): void { + $original_siteurl = get_option( 'siteurl' ); update_option( 'siteurl', 'http://example.org/wordpress' ); - self::assertSame( - 'http://example.org/wordpress/wp-admin/admin.php?page=parsely-settings', - self::$parsely::get_settings_url(), - 'The URL must reflect the subdirectory siteurl, not a hardcoded /wp-admin/ path.' - ); + try { + self::assertSame( + 'http://example.org/wordpress/wp-admin/admin.php?page=parsely-settings', + self::$parsely::get_settings_url(), + 'The URL must reflect the subdirectory siteurl, not a hardcoded /wp-admin/ path.' + ); + } finally { + update_option( 'siteurl', $original_siteurl ); + } } /** diff --git a/tests/Integration/UI/SiteHealthTest.php b/tests/Integration/UI/SiteHealthTest.php index e7dffeb8b..2469906f6 100644 --- a/tests/Integration/UI/SiteHealthTest.php +++ b/tests/Integration/UI/SiteHealthTest.php @@ -64,35 +64,40 @@ public function test_admin_bar_enqueued(): void { * @uses \Parsely\Parsely::site_id_is_missing */ public function test_check_site_id_uses_admin_url_for_subdirectory_install(): void { + $original_siteurl = get_option( 'siteurl' ); update_option( 'siteurl', 'http://example.org/wordpress' ); - // Re-instantiate so that get_settings_url() picks up the updated siteurl. - self::$site_health = new Site_Health( new Parsely() ); - - // Remove the Site ID to trigger the "critical" branch that renders the link. - self::set_options( array( 'apikey' => '' ) ); - - $tests = self::$site_health->check_site_id( array( 'direct' => array() ) ); - - // Assert the expected structure before drilling into it. This also - // narrows the types for static analysis. - self::assertIsArray( $tests['direct'] ); - self::assertIsArray( $tests['direct']['parsely'] ); - self::assertIsCallable( $tests['direct']['parsely']['test'] ); - - /** @var array{actions?: string} $result */ - $result = ( $tests['direct']['parsely']['test'] )(); - - self::assertStringContainsString( - 'http://example.org/wordpress/wp-admin/admin.php?page=parsely-settings', - $result['actions'] ?? '', - 'The actions link must reflect the subdirectory admin URL.' - ); - self::assertStringNotContainsString( - 'href="/wp-admin/', - $result['actions'] ?? '', - 'The actions link must not contain a hardcoded root /wp-admin/ path.' - ); + try { + // Re-instantiate so that get_settings_url() picks up the updated siteurl. + self::$site_health = new Site_Health( new Parsely() ); + + // Remove the Site ID to trigger the "critical" branch that renders the link. + self::set_options( array( 'apikey' => '' ) ); + + $tests = self::$site_health->check_site_id( array( 'direct' => array() ) ); + + // Assert the expected structure before drilling into it. This also + // narrows the types for static analysis. + self::assertIsArray( $tests['direct'] ); + self::assertIsArray( $tests['direct']['parsely'] ); + self::assertIsCallable( $tests['direct']['parsely']['test'] ); + + /** @var array{actions?: string} $result */ + $result = ( $tests['direct']['parsely']['test'] )(); + + self::assertStringContainsString( + 'http://example.org/wordpress/wp-admin/admin.php?page=parsely-settings', + $result['actions'] ?? '', + 'The actions link must reflect the subdirectory admin URL.' + ); + self::assertStringNotContainsString( + 'href="/wp-admin/', + $result['actions'] ?? '', + 'The actions link must not contain a hardcoded root /wp-admin/ path.' + ); + } finally { + update_option( 'siteurl', $original_siteurl ); + } } /** From e7c9bc2631be36221509ae5aefb5a6b3048bc517 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:26:54 +0000 Subject: [PATCH 25/31] Initial plan From 2eea2c298deb45fb6ad716cf106d20d95af84ed9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:36:14 +0000 Subject: [PATCH 26/31] Fix E2E tests: update selectors for tab-level VerifyCredentials message Agent-Logs-Url: https://github.com/Parsely/wp-parsely/sessions/087c3a49-1a10-4e35-a546-4d04a150b6ed Co-authored-by: acicovic <23142906+acicovic@users.noreply.github.com> --- .../specs/content-helper/top-bar-icon.spec.ts | 13 +++--- tests/e2e/utils.ts | 46 +++++++++++++++++-- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/tests/e2e/specs/content-helper/top-bar-icon.spec.ts b/tests/e2e/specs/content-helper/top-bar-icon.spec.ts index e952234ed..f225fd4c6 100644 --- a/tests/e2e/specs/content-helper/top-bar-icon.spec.ts +++ b/tests/e2e/specs/content-helper/top-bar-icon.spec.ts @@ -13,7 +13,7 @@ import { import { VALID_API_SECRET, VALID_SITE_ID, - setSidebarPanelExpanded, + getSidebarPanelOrTabMessage, setSiteKeys, } from '../../utils'; @@ -136,6 +136,10 @@ class Utils { * Tests the top bar icon by clicking on it and verifying that the PCH Editor * Sidebar opens. * + * When credentials are absent, the Related Posts panel is not rendered and + * the message appears at the tab level. In this case, the function returns + * the tab-level message without attempting to expand a panel. + * * @since 3.17.0 Migrated to Playwright. * * @param {string} siteId The Site ID to use for the test. @@ -152,13 +156,10 @@ class Utils { await setSiteKeys( page, siteId, apiSecret ); await this.admin.createNewPost(); - // Click the top bar icon and // Expand the Related Posts panel. + // Click the top bar icon. await page.getByRole( 'button', { name: 'Parse.ly' } ).click(); - setSidebarPanelExpanded( page, 'Related Posts', true ); - return await page.locator( - '.wp-parsely-content-helper div.components-panel__body.is-opened ' + selector - ).textContent() ?? ''; + return getSidebarPanelOrTabMessage( page, selector ); } /** diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 0e030729b..825da650a 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -39,6 +39,10 @@ export const setSiteKeys = async ( * Gets the message returned by the PHC Editor Sidebar Related Posts panel * according to the various conditions passed to the function. * + * When credentials are absent, the Related Posts panel is not rendered and the + * message appears at the tab level. In this case, the function returns the + * tab-level message without attempting to expand a panel. + * * @since 3.17.0 Migrated to Playwright. * * @param {Admin} admin The Admin object of the calling function. @@ -50,15 +54,49 @@ export const getRelatedPostsMessage = async ( admin: Admin, selector: string = '.content-helper-error-message' ): Promise => { const page = admin.page; - const contentHelperMessageSelector = '.wp-parsely-content-helper div.components-panel__body.is-opened ' + selector; await admin.createNewPost(); - // Show the Content Intelligence Sidebar and expand the Related Posts panel. + // Show the Content Intelligence Sidebar. await page.getByRole( 'button', { name: 'Parse.ly' } ).click(); - await setSidebarPanelExpanded( page, 'Related Posts', true ); - return await page.locator( contentHelperMessageSelector ).textContent() ?? ''; + return getSidebarPanelOrTabMessage( page, selector ); +}; + +/** + * Gets a message from the PCH Editor Sidebar, expanding the Related Posts + * panel when available, or reading the message from the tab level otherwise. + * + * When credentials are present, the Related Posts panel is visible and the + * message is found inside the opened panel body. When credentials are absent, + * the Related Posts panel is not rendered and the message appears at the tab + * level instead. + * + * @since 3.17.0 + * + * @param {Page} page The Page object of the calling function. + * @param {string} selector The selector from which to extract the message. + * + * @return {Promise} The message returned. + */ +export const getSidebarPanelOrTabMessage = async ( + page: Page, selector: string = '.content-helper-error-message' +): Promise => { + // Wait for the sidebar content to render. + await page.locator( '.wp-parsely-content-helper' ).waitFor( { state: 'visible' } ); + + const relatedPostsButton = page.getByRole( 'button', { name: 'Related Posts' } ); + + // When credentials are absent, the Related Posts panel is not shown and + // the message appears at the tab level. + if ( await relatedPostsButton.isVisible() ) { + await setSidebarPanelExpanded( page, 'Related Posts', true ); + return await page.locator( + '.wp-parsely-content-helper div.components-panel__body.is-opened ' + selector + ).textContent() ?? ''; + } + + return await page.locator( '.wp-parsely-content-helper ' + selector ).textContent() ?? ''; }; /** From e601df33a7018e704161a13b8c9be5376e777f80 Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:54:33 +0200 Subject: [PATCH 27/31] Attempt to fix failing E2E tests --- tests/e2e/specs/content-helper/top-bar-icon.spec.ts | 4 ---- tests/e2e/utils.ts | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/e2e/specs/content-helper/top-bar-icon.spec.ts b/tests/e2e/specs/content-helper/top-bar-icon.spec.ts index f225fd4c6..778523283 100644 --- a/tests/e2e/specs/content-helper/top-bar-icon.spec.ts +++ b/tests/e2e/specs/content-helper/top-bar-icon.spec.ts @@ -136,10 +136,6 @@ class Utils { * Tests the top bar icon by clicking on it and verifying that the PCH Editor * Sidebar opens. * - * When credentials are absent, the Related Posts panel is not rendered and - * the message appears at the tab level. In this case, the function returns - * the tab-level message without attempting to expand a panel. - * * @since 3.17.0 Migrated to Playwright. * * @param {string} siteId The Site ID to use for the test. diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 825da650a..5617184b4 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -39,10 +39,6 @@ export const setSiteKeys = async ( * Gets the message returned by the PHC Editor Sidebar Related Posts panel * according to the various conditions passed to the function. * - * When credentials are absent, the Related Posts panel is not rendered and the - * message appears at the tab level. In this case, the function returns the - * tab-level message without attempting to expand a panel. - * * @since 3.17.0 Migrated to Playwright. * * @param {Admin} admin The Admin object of the calling function. @@ -72,7 +68,7 @@ export const getRelatedPostsMessage = async ( * the Related Posts panel is not rendered and the message appears at the tab * level instead. * - * @since 3.17.0 + * @since 3.22.1 * * @param {Page} page The Page object of the calling function. * @param {string} selector The selector from which to extract the message. @@ -86,10 +82,13 @@ export const getSidebarPanelOrTabMessage = async ( await page.locator( '.wp-parsely-content-helper' ).waitFor( { state: 'visible' } ); const relatedPostsButton = page.getByRole( 'button', { name: 'Related Posts' } ); + const isRelatedPostsVisible = await relatedPostsButton.waitFor( { state: 'visible', timeout: 3000 } ) + .then( () => true ) + .catch( () => false ); // When credentials are absent, the Related Posts panel is not shown and // the message appears at the tab level. - if ( await relatedPostsButton.isVisible() ) { + if ( isRelatedPostsVisible ) { await setSidebarPanelExpanded( page, 'Related Posts', true ); return await page.locator( '.wp-parsely-content-helper div.components-panel__body.is-opened ' + selector From 21752227a111457117942ead75b20eb4ec2694dd Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:09:11 +0200 Subject: [PATCH 28/31] Fix typo --- tests/e2e/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 5617184b4..1b0ea548f 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -60,7 +60,7 @@ export const getRelatedPostsMessage = async ( }; /** - * Gets a message from the PCH Editor Sidebar, expanding the Related Posts + * Gets a message from the PCI Editor Sidebar, expanding the Related Posts * panel when available, or reading the message from the tab level otherwise. * * When credentials are present, the Related Posts panel is visible and the From b395fdf0f50f916801f4c312072192293d368c8a Mon Sep 17 00:00:00 2001 From: Alex Cicovic <23142906+acicovic@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:27:04 +0200 Subject: [PATCH 29/31] getSidebarPanelOrTabMessage(): Avoid timeout-based state fallback --- tests/e2e/utils.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 1b0ea548f..18c9ef7f4 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -82,20 +82,24 @@ export const getSidebarPanelOrTabMessage = async ( await page.locator( '.wp-parsely-content-helper' ).waitFor( { state: 'visible' } ); const relatedPostsButton = page.getByRole( 'button', { name: 'Related Posts' } ); - const isRelatedPostsVisible = await relatedPostsButton.waitFor( { state: 'visible', timeout: 3000 } ) - .then( () => true ) - .catch( () => false ); + const hasRelatedPostsPanel = ( await relatedPostsButton.count() ) > 0; // When credentials are absent, the Related Posts panel is not shown and // the message appears at the tab level. - if ( isRelatedPostsVisible ) { + if ( hasRelatedPostsPanel ) { await setSidebarPanelExpanded( page, 'Related Posts', true ); - return await page.locator( + const panelMessage = page.locator( '.wp-parsely-content-helper div.components-panel__body.is-opened ' + selector - ).textContent() ?? ''; + ); + await panelMessage.waitFor( { state: 'visible' } ); + + return ( await panelMessage.textContent() ) ?? ''; } - return await page.locator( '.wp-parsely-content-helper ' + selector ).textContent() ?? ''; + const tabMessage = page.locator( '.wp-parsely-content-helper ' + selector ); + await tabMessage.waitFor( { state: 'visible' } ); + + return ( await tabMessage.textContent() ) ?? ''; }; /** From e4926447f5482802b9df54c366950ef6e6c90c1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 30 Mar 2026 08:14:19 +0000 Subject: [PATCH 30/31] Update wp-parsely version number to 3.22.1 --- README.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- tests/e2e/utils.ts | 2 +- wp-parsely.php | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1f944ba21..e33776f98 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Parse.ly -Stable tag: 3.22.0 +Stable tag: 3.22.1 Requires at least: 6.0 Tested up to: 6.9 Requires PHP: 7.4 diff --git a/package-lock.json b/package-lock.json index 3b0a810cf..6cf3a1e15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wp-parsely", - "version": "3.22.0", + "version": "3.22.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wp-parsely", - "version": "3.22.0", + "version": "3.22.1", "license": "GPL-2.0-or-later", "dependencies": { "@types/js-cookie": "^3.0.6", diff --git a/package.json b/package.json index b595b82e3..823bf22d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wp-parsely", - "version": "3.22.0", + "version": "3.22.1", "private": true, "description": "The Parse.ly plugin facilitates real-time and historical analytics to your content through a platform designed and built for digital publishing.", "author": "parsely, hbbtstar, jblz, mikeyarce, GaryJ, parsely_mike, acicovic, mehmoodak, vaurdan", diff --git a/tests/e2e/utils.ts b/tests/e2e/utils.ts index 18c9ef7f4..66320221f 100644 --- a/tests/e2e/utils.ts +++ b/tests/e2e/utils.ts @@ -8,7 +8,7 @@ import { type Page } from '@playwright/test'; */ import { Admin } from '@wordpress/e2e-test-utils-playwright'; -export const PLUGIN_VERSION = '3.22.0'; +export const PLUGIN_VERSION = '3.22.1'; export const VALID_SITE_ID = 'demoaccount.parsely.com'; export const INVALID_SITE_ID = 'invalid.parsely.com'; export const VALID_API_SECRET = 'valid_api_secret'; diff --git a/wp-parsely.php b/wp-parsely.php index ab29c148c..59dbc003e 100644 --- a/wp-parsely.php +++ b/wp-parsely.php @@ -11,7 +11,7 @@ * Plugin Name: Parse.ly * Plugin URI: https://docs.parse.ly/wordpress * Description: This plugin makes it a snap to add Parse.ly tracking code and metadata to your WordPress blog. - * Version: 3.22.0 + * Version: 3.22.1 * Author: Parse.ly * Author URI: https://www.parse.ly * Text Domain: wp-parsely @@ -50,7 +50,7 @@ return; } -const PARSELY_VERSION = '3.22.0'; +const PARSELY_VERSION = '3.22.1'; const PARSELY_FILE = __FILE__; const PARSELY_DATA_SCHEMA_VERSION = '1'; const PARSELY_CACHE_GROUP = 'wp-parsely'; From 280cc62bc468de7ec4cc92111f1a8708ce6130a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 30 Mar 2026 08:14:25 +0000 Subject: [PATCH 31/31] Update CHANGELOG.md for version 3.22.1 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa8f82c00..f95e2873a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.22.1](https://github.com/Parsely/wp-parsely/compare/3.22.0...3.22.1) - 2026-03-30 + +### Fixed + +- PCI Sidebar: Fix multiple contact messages ([#4097](https://github.com/Parsely/wp-parsely/pull/4097)) +- Fix hardcoded wp-admin URLs ([#4095](https://github.com/Parsely/wp-parsely/pull/4095)) +- Fix apiVersion number mismatch ([#4061](https://github.com/Parsely/wp-parsely/pull/4061)) + +### Dependency Updates + +- The list of all dependency updates for this release is available [here](https://github.com/Parsely/wp-parsely/pulls?q=is%3Apr+is%3Amerged+milestone%3A3.22.1+label%3ADeps). + ## [3.22.0](https://github.com/Parsely/wp-parsely/compare/3.21.2...3.22.0) - 2026-01-12 ### Added