Merge branch 'fix/t18-live-detection-chain' into develop (#18)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
534
package-lock.json
generated
534
package-lock.json
generated
@ -23,6 +23,9 @@
|
|||||||
"sax": "^1.4.3",
|
"sax": "^1.4.3",
|
||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jsdom": "^22.1.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
@ -175,6 +178,16 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@tootallnate/once": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "10.17.60",
|
"version": "10.17.60",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
|
||||||
@ -182,6 +195,14 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/abab": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||||
|
"deprecated": "Use your platform's native atob() and btoa() methods instead",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
@ -199,8 +220,8 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
},
|
},
|
||||||
@ -212,8 +233,8 @@
|
|||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "^2.1.3"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
@ -230,8 +251,8 @@
|
|||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"license": "MIT",
|
"devOptional": true,
|
||||||
"optional": true
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
@ -239,6 +260,13 @@
|
|||||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
@ -414,6 +442,19 @@
|
|||||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-stream": {
|
"node_modules/concat-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||||
@ -466,6 +507,34 @@
|
|||||||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/cssstyle": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"rrweb-cssom": "^0.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/data-urls": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"abab": "^2.0.6",
|
||||||
|
"whatwg-mimetype": "^3.0.0",
|
||||||
|
"whatwg-url": "^12.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
@ -475,6 +544,13 @@
|
|||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decimal.js": {
|
||||||
|
"version": "10.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
|
||||||
|
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/decompress-response": {
|
"node_modules/decompress-response": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
@ -499,6 +575,16 @@
|
|||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@ -527,6 +613,20 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/domexception": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
|
||||||
|
"deprecated": "Use your platform's native DOMException instead",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"webidl-conversions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "17.2.3",
|
"version": "17.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||||
@ -586,6 +686,19 @@
|
|||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/env-paths": {
|
"node_modules/env-paths": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||||
@ -626,6 +739,22 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
@ -756,6 +885,23 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.4",
|
||||||
|
"mime-types": "^2.1.35"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
@ -856,10 +1002,26 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
@ -868,6 +1030,19 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-encoding-sniffer": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-encoding": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/http-errors": {
|
"node_modules/http-errors": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||||
@ -888,6 +1063,46 @@
|
|||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/http-proxy-agent": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tootallnate/once": "2",
|
||||||
|
"agent-base": "6",
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-agent/node_modules/debug": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-agent/node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/http-response-object": {
|
"node_modules/http-response-object": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
|
||||||
@ -902,8 +1117,8 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": "6",
|
"agent-base": "6",
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
@ -916,8 +1131,8 @@
|
|||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "^2.1.3"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
@ -934,8 +1149,8 @@
|
|||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"license": "MIT",
|
"devOptional": true,
|
||||||
"optional": true
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
@ -990,6 +1205,56 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-potential-custom-element-name": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jsdom": {
|
||||||
|
"version": "22.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
|
||||||
|
"integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"abab": "^2.0.6",
|
||||||
|
"cssstyle": "^3.0.0",
|
||||||
|
"data-urls": "^4.0.0",
|
||||||
|
"decimal.js": "^10.4.3",
|
||||||
|
"domexception": "^4.0.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"html-encoding-sniffer": "^3.0.0",
|
||||||
|
"http-proxy-agent": "^5.0.0",
|
||||||
|
"https-proxy-agent": "^5.0.1",
|
||||||
|
"is-potential-custom-element-name": "^1.0.1",
|
||||||
|
"nwsapi": "^2.2.4",
|
||||||
|
"parse5": "^7.1.2",
|
||||||
|
"rrweb-cssom": "^0.6.0",
|
||||||
|
"saxes": "^6.0.0",
|
||||||
|
"symbol-tree": "^3.2.4",
|
||||||
|
"tough-cookie": "^4.1.2",
|
||||||
|
"w3c-xmlserializer": "^4.0.0",
|
||||||
|
"webidl-conversions": "^7.0.0",
|
||||||
|
"whatwg-encoding": "^2.0.0",
|
||||||
|
"whatwg-mimetype": "^3.0.0",
|
||||||
|
"whatwg-url": "^12.0.1",
|
||||||
|
"ws": "^8.13.0",
|
||||||
|
"xml-name-validator": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"canvas": "^2.5.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"canvas": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsonwebtoken": {
|
"node_modules/jsonwebtoken": {
|
||||||
"version": "9.0.3",
|
"version": "9.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
|
||||||
@ -1210,6 +1475,13 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nwsapi": {
|
||||||
|
"version": "2.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.28.tgz",
|
||||||
|
"integrity": "sha512-IlVB7OS7qrOsVYlpnFIkETjMwT9jwvmocJmmM+GZU/PAB3uGi9Ezd7vcWhWBUnSc0ya4ppmQITOyP1ez9gg8cg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/oauth": {
|
"node_modules/oauth": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz",
|
||||||
@ -1264,6 +1536,19 @@
|
|||||||
"integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==",
|
"integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/parse5": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"entities": "^6.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@ -1397,6 +1682,19 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/psl": {
|
||||||
|
"version": "1.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
|
||||||
|
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "^2.3.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/lupomontero"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||||
@ -1407,6 +1705,16 @@
|
|||||||
"once": "^1.3.1"
|
"once": "^1.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/punycode": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.0",
|
"version": "6.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
@ -1422,6 +1730,13 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/querystringify": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/random-bytes": {
|
"node_modules/random-bytes": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||||
@ -1484,6 +1799,20 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/requires-port": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/rrweb-cssom": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/safe-buffer": {
|
"node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
@ -1516,6 +1845,19 @@
|
|||||||
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
|
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
|
||||||
"license": "BlueOak-1.0.0"
|
"license": "BlueOak-1.0.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/saxes": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"xmlchars": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=v12.22.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.7.3",
|
"version": "7.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||||
@ -1723,6 +2065,13 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/symbol-tree": {
|
||||||
|
"version": "3.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||||
|
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tar-fs": {
|
"node_modules/tar-fs": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||||
@ -1760,6 +2109,35 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tough-cookie": {
|
||||||
|
"version": "4.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
||||||
|
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"psl": "^1.1.33",
|
||||||
|
"punycode": "^2.1.1",
|
||||||
|
"universalify": "^0.2.0",
|
||||||
|
"url-parse": "^1.5.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tunnel-agent": {
|
"node_modules/tunnel-agent": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||||
@ -1804,6 +2182,16 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/universalify": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
@ -1813,6 +2201,17 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/url-parse": {
|
||||||
|
"version": "1.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||||
|
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"querystringify": "^2.1.1",
|
||||||
|
"requires-port": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
@ -1837,12 +2236,118 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/w3c-xmlserializer": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"xml-name-validator": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-encoding": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
|
||||||
|
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"iconv-lite": "0.6.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-mimetype": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "12.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
|
||||||
|
"integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "^4.1.1",
|
||||||
|
"webidl-conversions": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
|
||||||
|
"integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xml-name-validator": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xml2js": {
|
"node_modules/xml2js": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
|
||||||
@ -1864,6 +2369,13 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xmlchars": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,5 +29,8 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"jsdom": "^22.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -906,6 +906,13 @@ class ChannelList {
|
|||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.currentRenderId = null; // Reset render tracking
|
this.currentRenderId = null; // Reset render tracking
|
||||||
|
|
||||||
|
const previousState = {
|
||||||
|
channels: this.channels,
|
||||||
|
groups: this.groups,
|
||||||
|
visibleFavorites: this.visibleFavorites,
|
||||||
|
hiddenItems: this.hiddenItems
|
||||||
|
};
|
||||||
|
|
||||||
const sourceValue = this.sourceSelect.value;
|
const sourceValue = this.sourceSelect.value;
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
@ -943,7 +950,15 @@ class ChannelList {
|
|||||||
void this.refreshLayaLanguages();
|
void this.refreshLayaLanguages();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error loading channels:', err);
|
console.error('Error loading channels:', err);
|
||||||
this.container.innerHTML = `<div class="empty-state"><p>Error loading channels</p><p class="hint">${err.message}</p></div>`;
|
if (previousState.channels.length > 0) {
|
||||||
|
this.channels = previousState.channels;
|
||||||
|
this.groups = previousState.groups;
|
||||||
|
this.visibleFavorites = previousState.visibleFavorites;
|
||||||
|
this.hiddenItems = previousState.hiddenItems;
|
||||||
|
this.render();
|
||||||
|
} else {
|
||||||
|
this.container.innerHTML = `<div class="empty-state"><p>Error loading channels</p><p class="hint">${err.message}</p></div>`;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
@ -953,6 +968,12 @@ class ChannelList {
|
|||||||
* Load channels from all enabled sources
|
* Load channels from all enabled sources
|
||||||
*/
|
*/
|
||||||
async loadAllChannels() {
|
async loadAllChannels() {
|
||||||
|
const previousState = {
|
||||||
|
channels: this.channels,
|
||||||
|
groups: this.groups,
|
||||||
|
visibleFavorites: this.visibleFavorites,
|
||||||
|
hiddenItems: this.hiddenItems
|
||||||
|
};
|
||||||
this.channels = [];
|
this.channels = [];
|
||||||
this.groups = [];
|
this.groups = [];
|
||||||
|
|
||||||
@ -985,6 +1006,15 @@ class ChannelList {
|
|||||||
void this.refreshLayaLanguages();
|
void this.refreshLayaLanguages();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error loading all channels:', err);
|
console.error('Error loading all channels:', err);
|
||||||
|
if (previousState.channels.length > 0) {
|
||||||
|
this.channels = previousState.channels;
|
||||||
|
this.groups = previousState.groups;
|
||||||
|
this.visibleFavorites = previousState.visibleFavorites;
|
||||||
|
this.hiddenItems = previousState.hiddenItems;
|
||||||
|
this.render();
|
||||||
|
} else {
|
||||||
|
this.container.innerHTML = `<div class="empty-state"><p>Error loading channels</p><p class="hint">${err.message}</p></div>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canUse(response) {
|
function canUse(response) {
|
||||||
return Boolean(response && Array.isArray(response.channels) && !response.projection?.stale);
|
if (!response || !Array.isArray(response.channels) || response.projection?.stale) return false;
|
||||||
|
|
||||||
|
const projection = response.projection || {};
|
||||||
|
const expectedChannelCount = [
|
||||||
|
projection.total,
|
||||||
|
projection.processed,
|
||||||
|
projection.catalogCount,
|
||||||
|
projection.sourceChannelCount
|
||||||
|
].some(count => Number(count) > 0);
|
||||||
|
|
||||||
|
return response.channels.length > 0 || !expectedChannelCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { canUse, mapResponse };
|
return { canUse, mapResponse };
|
||||||
|
|||||||
@ -5,9 +5,10 @@ const liveProjection = require('../services/liveProjectionService');
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
function serializeState(state) {
|
function serializeState(state) {
|
||||||
|
const emptyProjectionWithLiveInput = state.total_count > 0 && state.projected_count === 0;
|
||||||
return {
|
return {
|
||||||
status: state.status,
|
status: state.status,
|
||||||
stale: state.status !== 'success',
|
stale: state.status !== 'success' || emptyProjectionWithLiveInput,
|
||||||
startedAt: state.started_at,
|
startedAt: state.started_at,
|
||||||
completedAt: state.completed_at,
|
completedAt: state.completed_at,
|
||||||
inputHash: state.input_hash,
|
inputHash: state.input_hash,
|
||||||
|
|||||||
257
test/liveAnalysisUserFlowDom.test.js
Normal file
257
test/liveAnalysisUserFlowDom.test.js
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { JSDOM } = require('jsdom');
|
||||||
|
|
||||||
|
const root = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
|
function readPublicScript(relativePath, exposeGlobal = '') {
|
||||||
|
const source = fs.readFileSync(path.join(root, 'public', relativePath), 'utf8');
|
||||||
|
return exposeGlobal ? `${source}\nwindow.${exposeGlobal} = ${exposeGlobal};` : source;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDom() {
|
||||||
|
const dom = new JSDOM(`<!doctype html>
|
||||||
|
<input id="channel-search">
|
||||||
|
<select id="source-select"><option value="">All Sources</option></select>
|
||||||
|
<input id="show-hidden" type="checkbox">
|
||||||
|
<button id="toggle-groups" type="button"></button>
|
||||||
|
<div id="context-menu"></div>
|
||||||
|
<div id="channel-list"></div>
|
||||||
|
|
||||||
|
<button type="button" id="live-analysis-button">Analyze channels</button>
|
||||||
|
<div id="live-analysis-status" role="status"></div>
|
||||||
|
<div id="live-analysis-progress" hidden>
|
||||||
|
<div id="live-analysis-progress-track"><span id="live-analysis-progress-bar"></span></div>
|
||||||
|
<div id="live-analysis-progress-text"></div>
|
||||||
|
</div>
|
||||||
|
<div id="live-analysis-fallback"></div>
|
||||||
|
<button type="button" id="live-analysis-details-toggle" hidden></button>
|
||||||
|
<pre id="live-analysis-error-details" hidden></pre>
|
||||||
|
`, {
|
||||||
|
url: 'http://nodecast.test/',
|
||||||
|
runScripts: 'outside-only',
|
||||||
|
pretendToBeVisual: true
|
||||||
|
});
|
||||||
|
const { window } = dom;
|
||||||
|
window.clearInterval = window.clearInterval.bind(window);
|
||||||
|
window.IntersectionObserver = class {
|
||||||
|
observe() {}
|
||||||
|
disconnect() {}
|
||||||
|
};
|
||||||
|
window.console = console;
|
||||||
|
window.eval(readPublicScript('js/icons.js'));
|
||||||
|
window.eval(readPublicScript('js/services/channelLanguageDetection.js'));
|
||||||
|
window.eval(readPublicScript('js/services/channelLanguageFusion.js'));
|
||||||
|
window.eval(readPublicScript('js/services/channelVariantGrouping.js'));
|
||||||
|
window.eval(readPublicScript('js/services/liveChannelProjection.js'));
|
||||||
|
window.eval(readPublicScript('js/services/layaStatusPresentation.js'));
|
||||||
|
window.eval(readPublicScript('js/services/liveAnalysisPresentation.js'));
|
||||||
|
window.eval(readPublicScript('js/components/ChannelList.js', 'ChannelList'));
|
||||||
|
window.eval(readPublicScript('js/pages/Settings.js', 'SettingsPage'));
|
||||||
|
return {
|
||||||
|
window
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function projectedChannels() {
|
||||||
|
return {
|
||||||
|
projection: { status: 'success', stale: false },
|
||||||
|
channels: [{
|
||||||
|
id: 'logical:sports-one',
|
||||||
|
fingerprint: 'sports one',
|
||||||
|
displayName: 'Sports One',
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: 'fr-sd',
|
||||||
|
sourceId: 1,
|
||||||
|
name: '|FR| Sports One SD',
|
||||||
|
groupTitle: 'Sports France',
|
||||||
|
categoryName: 'Sports France',
|
||||||
|
streamIcon: 'fr.png',
|
||||||
|
streamUrl: 'https://streams.test/fr-sd.m3u8',
|
||||||
|
tvgId: 'sports.one.fr',
|
||||||
|
isFavorite: true,
|
||||||
|
isHidden: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'en-4k',
|
||||||
|
sourceId: 1,
|
||||||
|
name: '|UK| Sports One 4K',
|
||||||
|
groupTitle: 'UK Sports',
|
||||||
|
categoryName: 'UK Sports',
|
||||||
|
streamIcon: 'en.png',
|
||||||
|
streamUrl: 'https://streams.test/en-4k.m3u8',
|
||||||
|
tvgId: 'sports.one.uk',
|
||||||
|
isFavorite: false,
|
||||||
|
isHidden: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('user analysis click keeps visible channels after Local AI language failure', async () => {
|
||||||
|
const { window } = createDom();
|
||||||
|
let rebuildClicked = 0;
|
||||||
|
let layaBatchCalls = 0;
|
||||||
|
let channelLoads = 0;
|
||||||
|
const consoleWarnings = [];
|
||||||
|
window.console = {
|
||||||
|
...console,
|
||||||
|
warn: (...args) => {
|
||||||
|
consoleWarnings.push(args.join(' '));
|
||||||
|
console.warn(...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.API = {
|
||||||
|
live: {
|
||||||
|
getChannels: async () => {
|
||||||
|
channelLoads += 1;
|
||||||
|
return projectedChannels();
|
||||||
|
},
|
||||||
|
rebuildProjection: async () => {
|
||||||
|
rebuildClicked += 1;
|
||||||
|
return { projection: { status: 'building', processed: 0, total: 2 } };
|
||||||
|
},
|
||||||
|
getProjectionStatus: async () => ({ status: 'success', processed: 2, total: 2, projectedCount: 1 })
|
||||||
|
},
|
||||||
|
laya: {
|
||||||
|
getStatus: async () => ({ modelPresent: true, runtimeAvailable: true }),
|
||||||
|
detectLanguages: async () => {
|
||||||
|
layaBatchCalls += 1;
|
||||||
|
throw new Error('simulated local AI language failure');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const app = {
|
||||||
|
player: {
|
||||||
|
settings: { liveChannelListMode: 'grouped', languageDetectionMode: 'algo' },
|
||||||
|
saveSettings() {}
|
||||||
|
},
|
||||||
|
epgGuide: null,
|
||||||
|
navigateTo() {},
|
||||||
|
pages: { settings: { switchTab() {} } }
|
||||||
|
};
|
||||||
|
window.app = app;
|
||||||
|
const channelList = new window.ChannelList();
|
||||||
|
channelList.sources = [{ id: 1, type: 'm3u', name: 'Fixture Provider' }];
|
||||||
|
app.channelList = channelList;
|
||||||
|
|
||||||
|
await channelList.loadChannels();
|
||||||
|
channelList.expandAll();
|
||||||
|
const beforeNames = [...window.document.querySelectorAll('.channel-name')].map(item => item.textContent);
|
||||||
|
assert.deepEqual(beforeNames, ['Sports One', 'Sports One']);
|
||||||
|
assert.equal(window.document.querySelector('.empty-state'), null);
|
||||||
|
|
||||||
|
app.player.settings.languageDetectionMode = 'hybrid';
|
||||||
|
const settingsPage = Object.create(window.SettingsPage.prototype);
|
||||||
|
settingsPage.app = app;
|
||||||
|
settingsPage.initLiveAnalysis();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
window.document.getElementById('live-analysis-button').click();
|
||||||
|
assert.equal(rebuildClicked, 1);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1100));
|
||||||
|
channelList.expandAll();
|
||||||
|
window.clearInterval(channelList._epgRefreshTimer);
|
||||||
|
window.clearInterval(settingsPage.liveAnalysisPollTimer);
|
||||||
|
|
||||||
|
const notice = window.document.querySelector('.laya-language-notice');
|
||||||
|
const afterNames = [...window.document.querySelectorAll('.channel-name')].map(item => item.textContent);
|
||||||
|
const languageBadges = [...window.document.querySelectorAll('.variant-language')].map(item => item.textContent);
|
||||||
|
const groupNames = [...window.document.querySelectorAll('.group-name')].map(item => item.textContent);
|
||||||
|
|
||||||
|
assert.equal(channelLoads, 2);
|
||||||
|
assert.equal(layaBatchCalls, 1);
|
||||||
|
assert.ok(notice);
|
||||||
|
assert.match(notice.textContent, /Local AI language detection failed/);
|
||||||
|
assert.deepEqual(afterNames, ['Sports One', 'Sports One']);
|
||||||
|
assert.deepEqual([...new Set(languageBadges)].sort(), ['EN 100%', 'FR 100%']);
|
||||||
|
assert.deepEqual(groupNames, ['Favorites', 'Sports France']);
|
||||||
|
assert.equal(window.document.querySelector('.empty-state'), null);
|
||||||
|
assert.equal(window.document.querySelector('#channel-list > .loading'), null);
|
||||||
|
assert.equal(channelList.languageDetectionFallback, true);
|
||||||
|
assert.equal(channelList.logicalChannels[0].variants.length, 2);
|
||||||
|
assert.ok(consoleWarnings.some(line => line.includes('Local AI language detection unavailable')));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('analysis click does not replace visible channels with an empty successful projection', async () => {
|
||||||
|
const { window } = createDom();
|
||||||
|
let rebuildClicked = 0;
|
||||||
|
let channelLoads = 0;
|
||||||
|
window.API = {
|
||||||
|
live: {
|
||||||
|
getChannels: async () => {
|
||||||
|
channelLoads += 1;
|
||||||
|
if (channelLoads === 1) return projectedChannels();
|
||||||
|
return {
|
||||||
|
projection: {
|
||||||
|
status: 'success',
|
||||||
|
stale: false,
|
||||||
|
projectedCount: 0,
|
||||||
|
processed: 3,
|
||||||
|
total: 3
|
||||||
|
},
|
||||||
|
channels: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
rebuildProjection: async () => {
|
||||||
|
rebuildClicked += 1;
|
||||||
|
return { projection: { status: 'building', processed: 0, total: 3 } };
|
||||||
|
},
|
||||||
|
getProjectionStatus: async () => ({ status: 'success', processed: 3, total: 3, projectedCount: 0 })
|
||||||
|
},
|
||||||
|
laya: {
|
||||||
|
getStatus: async () => ({ modelPresent: true, runtimeAvailable: true }),
|
||||||
|
detectLanguages: async () => {
|
||||||
|
throw new Error('simulated local AI language failure');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const app = {
|
||||||
|
player: {
|
||||||
|
settings: { liveChannelListMode: 'grouped', languageDetectionMode: 'hybrid' },
|
||||||
|
saveSettings() {}
|
||||||
|
},
|
||||||
|
epgGuide: null,
|
||||||
|
navigateTo() {},
|
||||||
|
pages: { settings: { switchTab() {} } }
|
||||||
|
};
|
||||||
|
window.app = app;
|
||||||
|
const channelList = new window.ChannelList();
|
||||||
|
channelList.sources = [{ id: 1, type: 'm3u', name: 'Fixture Provider', enabled: true }];
|
||||||
|
app.channelList = channelList;
|
||||||
|
|
||||||
|
await channelList.loadChannels();
|
||||||
|
channelList.expandAll();
|
||||||
|
const beforeNames = [...window.document.querySelectorAll('.channel-name')].map(item => item.textContent);
|
||||||
|
assert.deepEqual(beforeNames, ['Sports One', 'Sports One']);
|
||||||
|
assert.equal(window.document.querySelector('.empty-state'), null);
|
||||||
|
assert.equal(channelLoads, 1);
|
||||||
|
|
||||||
|
const settingsPage = Object.create(window.SettingsPage.prototype);
|
||||||
|
settingsPage.app = app;
|
||||||
|
settingsPage.initLiveAnalysis();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
window.document.getElementById('live-analysis-button').click();
|
||||||
|
assert.equal(rebuildClicked, 1);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1100));
|
||||||
|
channelList.expandAll();
|
||||||
|
window.clearInterval(channelList._epgRefreshTimer);
|
||||||
|
window.clearInterval(settingsPage.liveAnalysisPollTimer);
|
||||||
|
|
||||||
|
const afterNames = [...window.document.querySelectorAll('.channel-name')].map(item => item.textContent);
|
||||||
|
const emptyState = window.document.querySelector('.empty-state');
|
||||||
|
const loading = window.document.querySelector('#channel-list > .loading');
|
||||||
|
|
||||||
|
assert.equal(channelLoads, 2);
|
||||||
|
assert.deepEqual(afterNames, ['Sports One', 'Sports One']);
|
||||||
|
assert.equal(emptyState, null);
|
||||||
|
assert.equal(loading, null);
|
||||||
|
assert.equal(channelList.channels.length, 2);
|
||||||
|
});
|
||||||
166
test/liveDetectionFunctionalChain.test.js
Normal file
166
test/liveDetectionFunctionalChain.test.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const Database = require('better-sqlite3');
|
||||||
|
const {
|
||||||
|
ensureColumns,
|
||||||
|
LIVE_PROJECTION_COLUMNS,
|
||||||
|
LIVE_PROJECTION_SCHEMA_SQL
|
||||||
|
} = require('../server/db/liveProjectionSchema');
|
||||||
|
const liveProjection = require('../server/services/liveProjectionService');
|
||||||
|
const frontendProjection = require('../public/js/services/liveChannelProjection.js');
|
||||||
|
const grouping = require('../public/js/services/channelVariantGrouping.js');
|
||||||
|
const { channelListWarning } = require('../public/js/services/layaStatusPresentation.js');
|
||||||
|
|
||||||
|
function createFunctionalDb() {
|
||||||
|
const db = new Database(':memory:');
|
||||||
|
db.exec(`
|
||||||
|
CREATE TABLE categories (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
source_id INTEGER NOT NULL,
|
||||||
|
category_id TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
parent_id TEXT,
|
||||||
|
is_hidden INTEGER DEFAULT 0,
|
||||||
|
data JSON
|
||||||
|
);
|
||||||
|
CREATE TABLE playlist_items (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
source_id INTEGER NOT NULL,
|
||||||
|
item_id TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
category_id TEXT,
|
||||||
|
parent_id TEXT,
|
||||||
|
stream_icon TEXT,
|
||||||
|
stream_url TEXT,
|
||||||
|
container_extension TEXT,
|
||||||
|
rating REAL,
|
||||||
|
year TEXT,
|
||||||
|
added_at TEXT,
|
||||||
|
is_hidden INTEGER DEFAULT 0,
|
||||||
|
is_favorite INTEGER DEFAULT 0,
|
||||||
|
data JSON
|
||||||
|
);
|
||||||
|
CREATE TABLE favorites (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
source_id INTEGER NOT NULL,
|
||||||
|
item_id TEXT NOT NULL,
|
||||||
|
item_type TEXT NOT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(user_id, source_id, item_id, item_type)
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
ensureColumns(db, 'playlist_items', LIVE_PROJECTION_COLUMNS);
|
||||||
|
db.exec(LIVE_PROJECTION_SCHEMA_SQL);
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
function seedCategory(db, categoryId, name, extra = {}) {
|
||||||
|
db.prepare(`
|
||||||
|
INSERT INTO categories (id, source_id, category_id, type, name, is_hidden, data)
|
||||||
|
VALUES (?, 1, ?, 'live', ?, ?, '{}')
|
||||||
|
`).run(`1:${categoryId}`, categoryId, name, extra.isHidden ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function seedChannel(db, itemId, name, categoryId, extra = {}) {
|
||||||
|
db.prepare(`
|
||||||
|
INSERT INTO playlist_items
|
||||||
|
(id, source_id, item_id, type, name, category_id, stream_icon, stream_url, is_hidden, data)
|
||||||
|
VALUES (?, 1, ?, 'live', ?, ?, ?, ?, ?, ?)
|
||||||
|
`).run(
|
||||||
|
`1:${itemId}`,
|
||||||
|
itemId,
|
||||||
|
name,
|
||||||
|
categoryId,
|
||||||
|
`${itemId}.png`,
|
||||||
|
`https://streams.test/${itemId}.m3u8`,
|
||||||
|
extra.isHidden ? 1 : 0,
|
||||||
|
JSON.stringify({
|
||||||
|
tvgId: extra.tvgId || null,
|
||||||
|
groupTitle: extra.groupTitle || undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('functional live detection chain keeps categories and language selection correct after Laya fallback', async () => {
|
||||||
|
const db = createFunctionalDb();
|
||||||
|
seedCategory(db, 'sports-fr', 'Sports France');
|
||||||
|
seedCategory(db, 'sports-uk', 'UK Sports');
|
||||||
|
seedCategory(db, 'events', 'Sports Events');
|
||||||
|
seedChannel(db, 'fr-sd', '|FR| Sports One SD', 'sports-fr', { tvgId: 'sports.one.fr' });
|
||||||
|
seedChannel(db, 'fr-4k-hidden', '|FR| Sports One 4K', 'sports-fr', { isHidden: true, tvgId: 'sports.one.fr.4k' });
|
||||||
|
seedChannel(db, 'en-4k', '|UK| Sports One 4K', 'sports-uk', { tvgId: 'sports.one.uk' });
|
||||||
|
seedChannel(db, 'bein-main', 'beIN Sports 1 HD', 'events');
|
||||||
|
seedChannel(db, 'bein-event', 'Partner beIN Sports 1 Event', 'events');
|
||||||
|
db.prepare(`
|
||||||
|
INSERT INTO favorites (user_id, source_id, item_id, item_type)
|
||||||
|
VALUES (7, 1, 'fr-sd', 'channel')
|
||||||
|
`).run();
|
||||||
|
|
||||||
|
let layaRequests = 0;
|
||||||
|
const state = await liveProjection.rebuildWithSignals(db, {
|
||||||
|
mode: 'hybrid',
|
||||||
|
layaClient: {
|
||||||
|
identityHintBatch: async () => {
|
||||||
|
layaRequests += 1;
|
||||||
|
throw new Error('simulated local AI failure');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(layaRequests, 1);
|
||||||
|
assert.equal(state.status, 'success');
|
||||||
|
assert.equal(state.error, null);
|
||||||
|
|
||||||
|
const rawRows = db.prepare(`
|
||||||
|
SELECT item_id, logical_channel_id, grouping_fingerprint
|
||||||
|
FROM playlist_items
|
||||||
|
WHERE item_id IN ('fr-sd', 'fr-4k-hidden', 'en-4k')
|
||||||
|
ORDER BY item_id
|
||||||
|
`).all();
|
||||||
|
assert.deepEqual(rawRows.map(row => row.item_id), ['en-4k', 'fr-4k-hidden', 'fr-sd']);
|
||||||
|
assert.equal(new Set(rawRows.map(row => row.logical_channel_id)).size, 1);
|
||||||
|
assert.deepEqual([...new Set(rawRows.map(row => row.grouping_fingerprint))], ['sports one']);
|
||||||
|
|
||||||
|
const apiChannels = liveProjection.getChannels({ includeHidden: true, userId: 7 }, db);
|
||||||
|
const sportsOne = apiChannels.find(channel => channel.fingerprint === 'sports one');
|
||||||
|
assert.ok(sportsOne);
|
||||||
|
assert.deepEqual(
|
||||||
|
sportsOne.variants
|
||||||
|
.map(variant => [variant.id, variant.categoryName, variant.isHidden, variant.isFavorite])
|
||||||
|
.sort((left, right) => left[0].localeCompare(right[0])),
|
||||||
|
[
|
||||||
|
['en-4k', 'UK Sports', false, false],
|
||||||
|
['fr-4k-hidden', 'Sports France', true, false],
|
||||||
|
['fr-sd', 'Sports France', false, true]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const mapped = frontendProjection.mapResponse({
|
||||||
|
projection: { status: 'success', stale: false },
|
||||||
|
channels: apiChannels
|
||||||
|
}, [{ id: 1, type: 'm3u', name: 'Fixture Provider France' }]);
|
||||||
|
const warning = channelListWarning('hybrid', { modelPresent: true, runtimeAvailable: true }, true);
|
||||||
|
const logical = grouping.groupChannels(mapped.channels, {
|
||||||
|
languageMode: warning ? 'algo' : 'hybrid',
|
||||||
|
preferredLanguage: 'fr',
|
||||||
|
isFavorite: variant => mapped.favorites.has(`${variant.sourceId}:${variant.id}`),
|
||||||
|
isHidden: variant => mapped.hiddenItems.has(`channel:${variant.sourceId}:${variant.streamId || variant.id}`)
|
||||||
|
});
|
||||||
|
const frontendSportsOne = logical.find(channel => channel.fingerprint === 'sports one');
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
warning,
|
||||||
|
'Local AI language detection failed. Channels were grouped with Standard matching and remain available.'
|
||||||
|
);
|
||||||
|
assert.ok(frontendSportsOne);
|
||||||
|
assert.equal(frontendSportsOne.variants.length, 3);
|
||||||
|
assert.deepEqual(frontendSportsOne.availableLanguages.map(language => language.code).sort(), ['en', 'fr']);
|
||||||
|
assert.equal(frontendSportsOne.preferredVariant.id, 'fr-sd');
|
||||||
|
assert.equal(frontendSportsOne.preferredVariant.groupTitle, 'Sports France');
|
||||||
|
assert.equal(frontendSportsOne.isFavorite, true);
|
||||||
|
assert.equal(frontendSportsOne.isHidden, false);
|
||||||
|
assert.equal(grouping.orderFlatChannels(logical).length, logical.length);
|
||||||
|
});
|
||||||
@ -3,6 +3,7 @@ const assert = require('node:assert/strict');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { isAdmin } = require('../server/authz');
|
const { isAdmin } = require('../server/authz');
|
||||||
|
const { serializeState } = require('../server/routes/live');
|
||||||
|
|
||||||
const routeSource = fs.readFileSync(path.join(__dirname, '..', 'server', 'routes', 'live.js'), 'utf8');
|
const routeSource = fs.readFileSync(path.join(__dirname, '..', 'server', 'routes', 'live.js'), 'utf8');
|
||||||
|
|
||||||
@ -19,3 +20,19 @@ test('projection authorization distinguishes viewer and admin roles', () => {
|
|||||||
assert.equal(isAdmin({ role: 'admin' }), true);
|
assert.equal(isAdmin({ role: 'admin' }), true);
|
||||||
assert.equal(isAdmin(null), false);
|
assert.equal(isAdmin(null), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('projection success with live input but zero projected channels is exposed as stale', () => {
|
||||||
|
const state = serializeState({
|
||||||
|
status: 'success',
|
||||||
|
started_at: 100,
|
||||||
|
completed_at: 200,
|
||||||
|
input_hash: 'hash',
|
||||||
|
projected_count: 0,
|
||||||
|
processed_count: 3,
|
||||||
|
total_count: 3,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
assert.equal(state.stale, true);
|
||||||
|
assert.equal(state.projectedCount, 0);
|
||||||
|
assert.equal(state.total, 3);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user