diff --git a/package.json b/package.json index 27ca76da..d7dba3ee 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,12 @@ "format": "prettier --plugin prettier-plugin-svelte . --write ." }, "devDependencies": { - "@event-calendar/core": "^2.7.1", - "@event-calendar/day-grid": "^2.7.1", - "@event-calendar/list": "^2.7.1", + "@event-calendar/core": "^2.7.2", + "@event-calendar/day-grid": "^2.7.2", + "@event-calendar/list": "^2.7.2", "@iconify/svelte": "^4.0.2", "@sveltejs/adapter-node": "^5.0.1", - "@sveltejs/kit": "^2.5.9", + "@sveltejs/kit": "^2.5.10", "@sveltejs/vite-plugin-svelte": "^3.1.0", "@types/d3-array": "^3.2.1", "@types/d3-scale": "^4.0.8", @@ -25,8 +25,8 @@ "@types/express": "^4.17.21", "@types/js-yaml": "^4.0.9", "@types/promise-fs": "^2.1.5", - "@typescript-eslint/eslint-plugin": "^7.9.0", - "@typescript-eslint/parser": "^7.9.0", + "@typescript-eslint/eslint-plugin": "^7.10.0", + "@typescript-eslint/parser": "^7.10.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.39.0", @@ -46,7 +46,7 @@ "@codemirror/commands": "^6.5.0", "@codemirror/language": "^6.10.1", "@codemirror/legacy-modes": "^6.4.0", - "@codemirror/lint": "^6.7.1", + "@codemirror/lint": "^6.8.0", "@codemirror/state": "^6.4.1", "@codemirror/theme-one-dark": "^6.1.2", "@codemirror/view": "^6.26.3", @@ -62,7 +62,7 @@ "home-assistant-js-websocket": "^9.3.0", "http-proxy-middleware": "^3.0.0", "js-yaml": "^4.1.0", - "konva": "^9.3.8", + "konva": "^9.3.9", "maplibre-gl": "^4.3.2", "marked": "^12.0.2", "svelte-dnd-action": "^0.9.47", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e214e16c..2d8020ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^6.4.0 version: 6.4.0 '@codemirror/lint': - specifier: ^6.7.1 - version: 6.7.1 + specifier: ^6.8.0 + version: 6.8.0 '@codemirror/state': specifier: ^6.4.1 version: 6.4.1 @@ -69,8 +69,8 @@ importers: specifier: ^4.1.0 version: 4.1.0 konva: - specifier: ^9.3.8 - version: 9.3.8 + specifier: ^9.3.9 + version: 9.3.9 maplibre-gl: specifier: ^4.3.2 version: 4.3.2 @@ -97,23 +97,23 @@ importers: version: 9.4.0 devDependencies: '@event-calendar/core': - specifier: ^2.7.1 - version: 2.7.1 + specifier: ^2.7.2 + version: 2.7.2 '@event-calendar/day-grid': - specifier: ^2.7.1 - version: 2.7.1 + specifier: ^2.7.2 + version: 2.7.2 '@event-calendar/list': - specifier: ^2.7.1 - version: 2.7.1 + specifier: ^2.7.2 + version: 2.7.2 '@iconify/svelte': specifier: ^4.0.2 version: 4.0.2(svelte@4.2.17) '@sveltejs/adapter-node': specifier: ^5.0.1 - version: 5.0.1(@sveltejs/kit@2.5.9(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12))) + version: 5.0.1(@sveltejs/kit@2.5.10(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12))) '@sveltejs/kit': - specifier: ^2.5.9 - version: 2.5.9(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) + specifier: ^2.5.10 + version: 2.5.10(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) '@sveltejs/vite-plugin-svelte': specifier: ^3.1.0 version: 3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) @@ -136,11 +136,11 @@ importers: specifier: ^2.1.5 version: 2.1.5 '@typescript-eslint/eslint-plugin': - specifier: ^7.9.0 - version: 7.9.0(@typescript-eslint/parser@7.9.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.10.0 + version: 7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': - specifier: ^7.9.0 - version: 7.9.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.10.0 + version: 7.10.0(eslint@8.57.0)(typescript@5.4.5) eslint: specifier: ^8.57.0 version: 8.57.0 @@ -201,8 +201,8 @@ packages: '@codemirror/legacy-modes@6.4.0': resolution: {integrity: sha512-5m/K+1A6gYR0e+h/dEde7LoGimMjRtWXZFg4Lo70cc8HzjSdHe3fLwjWMR0VRl5KFT1SxalSap7uMgPKF28wBA==} - '@codemirror/lint@6.7.1': - resolution: {integrity: sha512-rELba6QJD20/bNXWP/cKTGLrwVEcpa2ViwULCV03ONcY1Je85++7sczVRUlnE4TJMjatx3IJTz6HX4NXi+moXw==} + '@codemirror/lint@6.8.0': + resolution: {integrity: sha512-lsFofvaw0lnPRJlQylNsC4IRt/1lI4OD/yYslrSGVndOJfStc58v+8p9dgGiD90ktOfL7OhBWns1ZETYgz0EJA==} '@codemirror/search@6.5.6': resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} @@ -372,14 +372,14 @@ packages: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@event-calendar/core@2.7.1': - resolution: {integrity: sha512-KqlSefS/D3Wh5EhaRdRpKxENH+jgR4aXoKygZqpRxAtB1GuckXL2IA6YavRc3PkiJNgCLuxfGMk3akMzwwAmQA==} + '@event-calendar/core@2.7.2': + resolution: {integrity: sha512-gH0JE0emGQpLMFPWY1BU+NdNRGv0byhZnzJRJnzV9jCnThUk8rOCJ6T4VcfGZwzlxg5L24hF0UOdTSec2LuOqw==} - '@event-calendar/day-grid@2.7.1': - resolution: {integrity: sha512-u4OCuLZz7VrAPOoh4b94HvJ+vIEbZY3+GPwJZ8pixi/fRjOxuPteippYL+mj7NT39NH+e8Lviy2EOmpR5vBbVw==} + '@event-calendar/day-grid@2.7.2': + resolution: {integrity: sha512-8x8Ujh1erSzZHDR0D9cqeECZENg6lmrCsHYSHL2gHaDNU+kG4kLqoane2zgImulST2VJ3OR/Q3ec14xXiHgCcA==} - '@event-calendar/list@2.7.1': - resolution: {integrity: sha512-k45cak5VbQnH091KoM8Ghav9aQmaOoNy/2bXIwCDCAfrzAayRtfnLmbHFJd35iI26QbTwhfHscl8CuSIN0LZsg==} + '@event-calendar/list@2.7.2': + resolution: {integrity: sha512-4g1ZuJcDsZ7W4BRP3hAxdO7TawI9rgAmthxxpr5BbdM7k3SPXeuIlAN8VAmHa4v9duHpDu0fBJ9/j/qgcZU5qg==} '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} @@ -483,8 +483,8 @@ packages: '@polka/url@1.0.0-next.25': resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} - '@rollup/plugin-commonjs@25.0.7': - resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==} + '@rollup/plugin-commonjs@25.0.8': + resolution: {integrity: sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -519,83 +519,83 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.17.2': - resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} + '@rollup/rollup-android-arm-eabi@4.18.0': + resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.17.2': - resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} + '@rollup/rollup-android-arm64@4.18.0': + resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.17.2': - resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} + '@rollup/rollup-darwin-arm64@4.18.0': + resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.17.2': - resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} + '@rollup/rollup-darwin-x64@4.18.0': + resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} + '@rollup/rollup-linux-arm-musleabihf@4.18.0': + resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.17.2': - resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} + '@rollup/rollup-linux-arm64-gnu@4.18.0': + resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.17.2': - resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} + '@rollup/rollup-linux-arm64-musl@4.18.0': + resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} + '@rollup/rollup-linux-riscv64-gnu@4.18.0': + resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.17.2': - resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} + '@rollup/rollup-linux-s390x-gnu@4.18.0': + resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.17.2': - resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} + '@rollup/rollup-linux-x64-gnu@4.18.0': + resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.17.2': - resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} + '@rollup/rollup-linux-x64-musl@4.18.0': + resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.17.2': - resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} + '@rollup/rollup-win32-arm64-msvc@4.18.0': + resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.17.2': - resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} + '@rollup/rollup-win32-ia32-msvc@4.18.0': + resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.17.2': - resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} + '@rollup/rollup-win32-x64-msvc@4.18.0': + resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} cpu: [x64] os: [win32] @@ -604,8 +604,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.4.0 - '@sveltejs/kit@2.5.9': - resolution: {integrity: sha512-x8biUVHPQq075/ESH/UO+fwENtAcw0kg9+bloqqEnbLUNWcrWpmcL3vKrKJc4vaVh/CYKFXn47N98Sbt/Y3vKQ==} + '@sveltejs/kit@2.5.10': + resolution: {integrity: sha512-OqoyTmFG2cYmCFAdBfW+Qxbg8m23H4dv6KqwEt7ofr/ROcfcIl3Z/VT56L22H9f0uNZyr+9Bs1eh2gedOCK9kA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -655,8 +655,8 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/express-serve-static-core@4.19.0': - resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==} + '@types/express-serve-static-core@4.19.1': + resolution: {integrity: sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==} '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} @@ -718,8 +718,8 @@ packages: '@types/supercluster@7.1.3': resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==} - '@typescript-eslint/eslint-plugin@7.9.0': - resolution: {integrity: sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==} + '@typescript-eslint/eslint-plugin@7.10.0': + resolution: {integrity: sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -729,8 +729,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.9.0': - resolution: {integrity: sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==} + '@typescript-eslint/parser@7.10.0': + resolution: {integrity: sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -739,12 +739,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@7.9.0': - resolution: {integrity: sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==} + '@typescript-eslint/scope-manager@7.10.0': + resolution: {integrity: sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.9.0': - resolution: {integrity: sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==} + '@typescript-eslint/type-utils@7.10.0': + resolution: {integrity: sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -753,12 +753,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@7.9.0': - resolution: {integrity: sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==} + '@typescript-eslint/types@7.10.0': + resolution: {integrity: sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/typescript-estree@7.9.0': - resolution: {integrity: sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==} + '@typescript-eslint/typescript-estree@7.10.0': + resolution: {integrity: sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -766,14 +766,14 @@ packages: typescript: optional: true - '@typescript-eslint/utils@7.9.0': - resolution: {integrity: sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==} + '@typescript-eslint/utils@7.10.0': + resolution: {integrity: sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/visitor-keys@7.9.0': - resolution: {integrity: sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==} + '@typescript-eslint/visitor-keys@7.10.0': + resolution: {integrity: sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': @@ -849,8 +849,8 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} buffer-crc32@0.2.13: @@ -1167,8 +1167,8 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} finalhandler@1.2.0: @@ -1335,6 +1335,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1445,8 +1446,8 @@ packages: known-css-properties@0.31.0: resolution: {integrity: sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==} - konva@9.3.8: - resolution: {integrity: sha512-acfS9hSBI0186DVjP4hnCgVQUGg5USn2I9U18skbOG+wFaVB2d84CmUNBfBAPTqsYjO5A0+qHZh7nj20UMNUEA==} + konva@9.3.9: + resolution: {integrity: sha512-0ACsA2kCGilptQqosTVdu5g1jAeONZI/W/L5U7afeRhoWqSV+HjcuBB+vsFzs64oL/02y+4/jd3K5RL0sLCxbQ==} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} @@ -1496,8 +1497,8 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -1661,8 +1662,8 @@ packages: peerDependencies: postcss: ^8.4.29 - postcss-selector-parser@6.0.16: - resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + postcss-selector-parser@6.1.0: + resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} engines: {node: '>=4'} postcss@8.4.38: @@ -1749,8 +1750,8 @@ packages: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true - rollup@4.17.2: - resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} + rollup@4.18.0: + resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1915,8 +1916,8 @@ packages: peerDependencies: svelte: ^3.0.0 || ^4.0.0 - svelte-parse-markup@0.1.3: - resolution: {integrity: sha512-Y1cH3r31SsuK1+jRwZs9amlE+NN7XnrADBUOTC2Nh9Ak3C50qMS2DqaxT0wJ/D8Pd2FElGnASAf38gQygtRtRg==} + svelte-parse-markup@0.1.4: + resolution: {integrity: sha512-cU6yFDQVn1m4gqhTwgfzQP9//MgEG9nYqiGtLRjjhYtV8XEtNA/1FK+gPF4lEkfQzYjsEUPqYT0IuTFaeScGHQ==} peerDependencies: svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 @@ -2155,7 +2156,7 @@ snapshots: dependencies: '@codemirror/language': 6.10.1 - '@codemirror/lint@6.7.1': + '@codemirror/lint@6.8.0': dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.26.3 @@ -2274,18 +2275,18 @@ snapshots: '@eslint/js@8.57.0': {} - '@event-calendar/core@2.7.1': + '@event-calendar/core@2.7.2': dependencies: svelte: 4.2.17 - '@event-calendar/day-grid@2.7.1': + '@event-calendar/day-grid@2.7.2': dependencies: - '@event-calendar/core': 2.7.1 + '@event-calendar/core': 2.7.2 svelte: 4.2.17 - '@event-calendar/list@2.7.1': + '@event-calendar/list@2.7.2': dependencies: - '@event-calendar/core': 2.7.1 + '@event-calendar/core': 2.7.2 svelte: 4.2.17 '@fastify/busboy@2.1.1': {} @@ -2389,99 +2390,99 @@ snapshots: '@polka/url@1.0.0-next.25': {} - '@rollup/plugin-commonjs@25.0.7(rollup@4.17.2)': + '@rollup/plugin-commonjs@25.0.8(rollup@4.18.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) commondir: 1.0.1 estree-walker: 2.0.2 glob: 8.1.0 is-reference: 1.2.1 magic-string: 0.30.10 optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/plugin-json@6.1.0(rollup@4.17.2)': + '@rollup/plugin-json@6.1.0(rollup@4.18.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/plugin-node-resolve@15.2.3(rollup@4.17.2)': + '@rollup/plugin-node-resolve@15.2.3(rollup@4.18.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 resolve: 1.22.8 optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/pluginutils@5.1.0(rollup@4.17.2)': + '@rollup/pluginutils@5.1.0(rollup@4.18.0)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/rollup-android-arm-eabi@4.17.2': + '@rollup/rollup-android-arm-eabi@4.18.0': optional: true - '@rollup/rollup-android-arm64@4.17.2': + '@rollup/rollup-android-arm64@4.18.0': optional: true - '@rollup/rollup-darwin-arm64@4.17.2': + '@rollup/rollup-darwin-arm64@4.18.0': optional: true - '@rollup/rollup-darwin-x64@4.17.2': + '@rollup/rollup-darwin-x64@4.18.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.17.2': + '@rollup/rollup-linux-arm-musleabihf@4.18.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.17.2': + '@rollup/rollup-linux-arm64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.17.2': + '@rollup/rollup-linux-arm64-musl@4.18.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.17.2': + '@rollup/rollup-linux-riscv64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.17.2': + '@rollup/rollup-linux-s390x-gnu@4.18.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.17.2': + '@rollup/rollup-linux-x64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-x64-musl@4.17.2': + '@rollup/rollup-linux-x64-musl@4.18.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.17.2': + '@rollup/rollup-win32-arm64-msvc@4.18.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.17.2': + '@rollup/rollup-win32-ia32-msvc@4.18.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.17.2': + '@rollup/rollup-win32-x64-msvc@4.18.0': optional: true - '@sveltejs/adapter-node@5.0.1(@sveltejs/kit@2.5.9(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))': + '@sveltejs/adapter-node@5.0.1(@sveltejs/kit@2.5.10(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))': dependencies: - '@rollup/plugin-commonjs': 25.0.7(rollup@4.17.2) - '@rollup/plugin-json': 6.1.0(rollup@4.17.2) - '@rollup/plugin-node-resolve': 15.2.3(rollup@4.17.2) - '@sveltejs/kit': 2.5.9(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) - rollup: 4.17.2 + '@rollup/plugin-commonjs': 25.0.8(rollup@4.18.0) + '@rollup/plugin-json': 6.1.0(rollup@4.18.0) + '@rollup/plugin-node-resolve': 15.2.3(rollup@4.18.0) + '@sveltejs/kit': 2.5.10(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) + rollup: 4.18.0 - '@sveltejs/kit@2.5.9(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12))': + '@sveltejs/kit@2.5.10(@sveltejs/vite-plugin-svelte@3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)))(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12))': dependencies: '@sveltejs/vite-plugin-svelte': 3.1.0(svelte@4.2.17)(vite@5.2.11(@types/node@20.12.12)) '@types/cookie': 0.6.0 @@ -2549,7 +2550,7 @@ snapshots: '@types/estree@1.0.5': {} - '@types/express-serve-static-core@4.19.0': + '@types/express-serve-static-core@4.19.1': dependencies: '@types/node': 20.12.12 '@types/qs': 6.9.15 @@ -2559,7 +2560,7 @@ snapshots: '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.0 + '@types/express-serve-static-core': 4.19.1 '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 @@ -2622,14 +2623,14 @@ snapshots: dependencies: '@types/geojson': 7946.0.14 - '@typescript-eslint/eslint-plugin@7.9.0(@typescript-eslint/parser@7.9.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.9.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.9.0 - '@typescript-eslint/type-utils': 7.9.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.9.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.9.0 + '@typescript-eslint/parser': 7.10.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.10.0 + '@typescript-eslint/type-utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.10.0 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -2640,12 +2641,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.9.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 7.9.0 - '@typescript-eslint/types': 7.9.0 - '@typescript-eslint/typescript-estree': 7.9.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.9.0 + '@typescript-eslint/scope-manager': 7.10.0 + '@typescript-eslint/types': 7.10.0 + '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.10.0 debug: 4.3.4 eslint: 8.57.0 optionalDependencies: @@ -2653,15 +2654,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@7.9.0': + '@typescript-eslint/scope-manager@7.10.0': dependencies: - '@typescript-eslint/types': 7.9.0 - '@typescript-eslint/visitor-keys': 7.9.0 + '@typescript-eslint/types': 7.10.0 + '@typescript-eslint/visitor-keys': 7.10.0 - '@typescript-eslint/type-utils@7.9.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.9.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.9.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) + '@typescript-eslint/utils': 7.10.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) @@ -2670,12 +2671,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@7.9.0': {} + '@typescript-eslint/types@7.10.0': {} - '@typescript-eslint/typescript-estree@7.9.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.10.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.9.0 - '@typescript-eslint/visitor-keys': 7.9.0 + '@typescript-eslint/types': 7.10.0 + '@typescript-eslint/visitor-keys': 7.10.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -2687,20 +2688,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.9.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.10.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.9.0 - '@typescript-eslint/types': 7.9.0 - '@typescript-eslint/typescript-estree': 7.9.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.10.0 + '@typescript-eslint/types': 7.10.0 + '@typescript-eslint/typescript-estree': 7.10.0(typescript@5.4.5) eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@7.9.0': + '@typescript-eslint/visitor-keys@7.10.0': dependencies: - '@typescript-eslint/types': 7.9.0 + '@typescript-eslint/types': 7.10.0 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -2782,9 +2783,9 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: + braces@3.0.3: dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 buffer-crc32@0.2.13: {} @@ -2819,7 +2820,7 @@ snapshots: chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -2841,7 +2842,7 @@ snapshots: '@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1) '@codemirror/commands': 6.5.0 '@codemirror/language': 6.10.1 - '@codemirror/lint': 6.7.1 + '@codemirror/lint': 6.8.0 '@codemirror/search': 6.5.6 '@codemirror/state': 6.4.1 '@codemirror/view': 6.26.3 @@ -3020,7 +3021,7 @@ snapshots: postcss: 8.4.38 postcss-load-config: 3.1.4(postcss@8.4.38) postcss-safe-parser: 6.0.0(postcss@8.4.38) - postcss-selector-parser: 6.0.16 + postcss-selector-parser: 6.1.0 semver: 7.6.2 svelte-eslint-parser: 0.36.0(svelte@4.2.17) optionalDependencies: @@ -3162,7 +3163,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-json-stable-stringify@2.1.0: {} @@ -3176,7 +3177,7 @@ snapshots: dependencies: flat-cache: 3.2.0 - fill-range@7.0.1: + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -3325,7 +3326,7 @@ snapshots: http-proxy: 1.18.1(debug@4.3.4) is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.5 + micromatch: 4.0.7 transitivePeerDependencies: - supports-color @@ -3443,7 +3444,7 @@ snapshots: known-css-properties@0.31.0: {} - konva@9.3.8: {} + konva@9.3.9: {} levn@0.4.1: dependencies: @@ -3506,9 +3507,9 @@ snapshots: methods@1.1.2: {} - micromatch@4.0.5: + micromatch@4.0.7: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 mime-db@1.52.0: {} @@ -3634,7 +3635,7 @@ snapshots: dependencies: postcss: 8.4.38 - postcss-selector-parser@6.0.16: + postcss-selector-parser@6.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -3712,26 +3713,26 @@ snapshots: dependencies: glob: 7.2.3 - rollup@4.17.2: + rollup@4.18.0: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.17.2 - '@rollup/rollup-android-arm64': 4.17.2 - '@rollup/rollup-darwin-arm64': 4.17.2 - '@rollup/rollup-darwin-x64': 4.17.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 - '@rollup/rollup-linux-arm-musleabihf': 4.17.2 - '@rollup/rollup-linux-arm64-gnu': 4.17.2 - '@rollup/rollup-linux-arm64-musl': 4.17.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 - '@rollup/rollup-linux-riscv64-gnu': 4.17.2 - '@rollup/rollup-linux-s390x-gnu': 4.17.2 - '@rollup/rollup-linux-x64-gnu': 4.17.2 - '@rollup/rollup-linux-x64-musl': 4.17.2 - '@rollup/rollup-win32-arm64-msvc': 4.17.2 - '@rollup/rollup-win32-ia32-msvc': 4.17.2 - '@rollup/rollup-win32-x64-msvc': 4.17.2 + '@rollup/rollup-android-arm-eabi': 4.18.0 + '@rollup/rollup-android-arm64': 4.18.0 + '@rollup/rollup-darwin-arm64': 4.18.0 + '@rollup/rollup-darwin-x64': 4.18.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 + '@rollup/rollup-linux-arm-musleabihf': 4.18.0 + '@rollup/rollup-linux-arm64-gnu': 4.18.0 + '@rollup/rollup-linux-arm64-musl': 4.18.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 + '@rollup/rollup-linux-riscv64-gnu': 4.18.0 + '@rollup/rollup-linux-s390x-gnu': 4.18.0 + '@rollup/rollup-linux-x64-gnu': 4.18.0 + '@rollup/rollup-linux-x64-musl': 4.18.0 + '@rollup/rollup-win32-arm64-msvc': 4.18.0 + '@rollup/rollup-win32-ia32-msvc': 4.18.0 + '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 run-parallel@1.2.0: @@ -3919,7 +3920,7 @@ snapshots: dependencies: magic-string: 0.30.10 svelte: 4.2.17 - svelte-parse-markup: 0.1.3(svelte@4.2.17) + svelte-parse-markup: 0.1.4(svelte@4.2.17) svelte-hmr@0.16.0(svelte@4.2.17): dependencies: @@ -3929,7 +3930,7 @@ snapshots: dependencies: svelte: 4.2.17 - svelte-parse-markup@0.1.3(svelte@4.2.17): + svelte-parse-markup@0.1.4(svelte@4.2.17): dependencies: svelte: 4.2.17 @@ -4038,7 +4039,7 @@ snapshots: dependencies: esbuild: 0.20.2 postcss: 8.4.38 - rollup: 4.17.2 + rollup: 4.18.0 optionalDependencies: '@types/node': 20.12.12 fsevents: 2.3.3 diff --git a/src/lib/Modal/YoutubeModal.svelte b/src/lib/Modal/YoutubeModal.svelte index cd06016a..6769ba2e 100644 --- a/src/lib/Modal/YoutubeModal.svelte +++ b/src/lib/Modal/YoutubeModal.svelte @@ -2,55 +2,103 @@ import Modal from '$lib/Modal/Index.svelte'; import ConfigButtons from '$lib/Modal/ConfigButtons.svelte'; import { base } from '$app/paths'; - import { onDestroy, onMount, tick } from 'svelte'; + import { onDestroy, onMount } from 'svelte'; import { closeModal } from 'svelte-modals'; import { lang, motion, ripple, youtubeAddon } from '$lib/Stores'; import { slide } from 'svelte/transition'; import Ripple from 'svelte-ripple'; + import type { YouTubeEvent } from '$lib/Types'; export let isOpen: boolean; - let message: any; - let evtSource: EventSource; + let interval: ReturnType; + let controller: AbortController; + let event: YouTubeEvent | undefined; + let data: any; let copied = false; + let inputCode: HTMLInputElement; - $: if (message?.error) console.error(message?.error); + /** + * If no credentials are saved, it starts the auth flow + * otherwise returns the user account. + */ + async function initialize() { + controller = new AbortController(); - $: data = message?.data?.contents?.contents?.[0]; - $: user = data?.account_name?.text; - $: img = data?.account_photo?.[0]?.url; - - const regexUrl = /\[ *\{url\} *\]\( *\{url\} *\)/g; - - $: url = message?.verification_url; - $: code = message?.user_code; - - $: authMessage = - url && - $lang('google_code') && - regexUrl.test($lang('google_code')) && - $lang('google_code').includes('{user_code}') && - $lang('google_code') - .replace(regexUrl, `${url}`) - .replace('{user_code}', ''); - - function signIn() { - evtSource = new EventSource(`${base}/_api/youtube`); - - evtSource.onmessage = (event) => { - message = JSON.parse(event.data); + try { + const response = await fetch(`${base}/_api/youtube`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + signal: controller?.signal + }); - // close after data is recieved - if (message?.data) evtSource.close(); - }; + const result = await response.json(); + data = result; + clearInterval(interval); + } catch (err: any) { + if (err?.name === 'AbortError') { + // ignore + } else { + event = { message: 'error', error: 'Failed to initiate authentication' }; + console.error('Failed to initiate authentication:', err); + } + clearInterval(interval); + } + } - // error - evtSource.onerror = (err) => { - console.error('EventSource failed:', err); - evtSource.close(); - }; + /** + * Polls for events, specifically 'auth-pending'. + * Server-Sent Events (SSE) do not work with ingress... + */ + async function pollEvents() { + const start = new Date().getTime(); + let attempts = 0; + + interval = setInterval(async () => { + // console.debug('polling...'); + + try { + const response = await fetch(`${base}/_api/youtube`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + message: 'poll' + }) + }); + const result = await response.json(); + + attempts++; + + // make sure data is not stale + if (!result?.timestamp || result.timestamp > start) { + event = result; + } + + if (result?.message === 'auth' || result?.message === 'auth-error') { + clearInterval(interval); + } + + // stop polling after 5 attempts if no data is received + if (attempts >= 5 && !event) { + event = { message: 'error', error: 'No valid response in 5 attempts' }; + clearInterval(interval); + } + } catch (err) { + event = { message: 'error', error: 'Polling failed' }; + console.error('Polling error:', err); + clearInterval(interval); + } + }, 1000); } + /** + * Signs out the user by sending a logout request to the server. + * Deactivates the add-on and closes the modal. + */ async function signOut() { try { const response = await fetch(`${base}/_api/youtube`, { @@ -58,29 +106,34 @@ headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ action: 'sign-out' }) + body: JSON.stringify({ + message: 'logout' + }) }); - if (response.ok) { - const result = await response.text(); - console.log(result); - - await tick(); - + const result = await response.json(); + if (result?.message === 'success') { $youtubeAddon = false; closeModal(); } else { - message.error = 'Failed to sign out'; + console.error(result); } - } catch (error) { - console.error('Error signing out:', error); + } catch (err) { + console.error('Failed to sign out:', err); } } - async function copyCode(user_code: string) { + /** + * Copies a given user code to the clipboard. + * Doesn't work with ingress, have to manually copy. + */ + async function copyCode(user_code: string | undefined) { + if (!user_code) return; + try { - await navigator.clipboard.writeText(user_code); + inputCode?.select(); + await navigator.clipboard.writeText(user_code); copied = true; setTimeout(() => (copied = false), $motion * 2); } catch (err: any) { @@ -89,36 +142,53 @@ } } - onMount(() => signIn()); + onMount(() => { + initialize(); + pollEvents(); + }); - onDestroy(() => evtSource?.close?.()); + onDestroy(() => { + clearInterval(interval); + controller?.abort?.(); + }); + { + controller?.abort?.(); + }} +/> + {#if isOpen}

YouTube

- {#if user && img} -

{$lang('manage_account')}

- {:else if url && code} -

{$lang('log_in')}

- {:else} -

{$lang('loading')}

- {/if} -
- - {#if user && img} + + {#if data} +

{$lang('manage_account')}

+ {:else if !event} +

{$lang('loading')}

+ {:else if event?.message === 'auth-pending'} +

{$lang('log_in')}

+ {/if} + + + {#if data} + {@const contents = data?.contents?.contents?.[0]} + {@const account_name = contents?.account_name?.text} + {@const account_photo = contents?.account_photo?.[0]?.url} +
- - {:else if url && code} -
- + + {:else if event?.message === 'auth-pending'} + {@const verification_url = event?.verification_url} + {@const user_code = event?.user_code} + + {@const regex = /\[ *\{url\} *\]\( *\{url\} *\)/g} + {@const localeAuthMessage = + verification_url && + $lang('google_code') && + regex.test($lang('google_code')) && + $lang('google_code').includes('{user_code}') && + $lang('google_code') + .replace(regex, `${verification_url}`) + .replace('{user_code}', '')} - {#if authMessage} - {@html authMessage} +
+ {#if localeAuthMessage} + {@html localeAuthMessage} {:else} - To link your Google account, visit the {url} and enter - code: + To link your Google account, visit the + {verification_url} and enter code: {/if}
- + on:click={() => copyCode(user_code)} + style:transition="background-color {$motion}ms" + type="text" + value={user_code} + readonly + />
+ + +
+ {/if} + + {#if event?.message === 'error'} +
+ Error: {event?.error}
{/if}
@@ -171,14 +262,18 @@ } .code { - all: unset; - margin-top: 1.5rem; + border: none; + color: white; user-select: text; - font-size: 1.5rem; + font-size: 1.35rem; background-color: var(--theme-button-background-color-off); - padding: 0.8rem 1rem; border-radius: 0.6rem; cursor: pointer; + width: 17rem; + padding: 1.1rem 0; + text-align: center; + letter-spacing: 0.4rem; + margin-top: 2rem; } .copied { @@ -190,6 +285,7 @@ padding: 1rem; display: flex; border-radius: 0.6rem; + height: 4.2rem; } .user-info { @@ -212,4 +308,9 @@ overflow: hidden; text-overflow: ellipsis; } + + .error { + color: red; + margin-top: 1rem; + } diff --git a/src/lib/Types.ts b/src/lib/Types.ts index 3a57bd62..6c23c78e 100644 --- a/src/lib/Types.ts +++ b/src/lib/Types.ts @@ -256,3 +256,11 @@ export interface WeatherForecastItem { days_to_show?: number; hide_mobile?: boolean; } + +export interface YouTubeEvent { + message: 'auth-pending' | 'auth' | 'update-credentials' | 'auth-error' | 'error'; + verification_url?: string; + user_code?: string; + timestamp?: number; + error?: any; +} diff --git a/src/routes/_api/youtube/+server.ts b/src/routes/_api/youtube/+server.ts index d4934367..e7021ccc 100644 --- a/src/routes/_api/youtube/+server.ts +++ b/src/routes/_api/youtube/+server.ts @@ -1,165 +1,62 @@ import { readFileSync, writeFileSync, unlinkSync } from 'fs'; import { Innertube, UniversalCache } from 'youtubei.js'; import { error, json, type RequestHandler } from '@sveltejs/kit'; +import type { YouTubeEvent } from '$lib/Types'; import yaml from 'js-yaml'; -interface Event { - message?: string; - error?: string; - data?: any; - verification_url?: string; - user_code?: string; -} - let youtube: Innertube | undefined; +let event: YouTubeEvent | undefined; -/** - * GET: Streams server-sent events to client in add-on settings. - */ -export const GET: RequestHandler = async () => { - const headers = { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - Connection: 'keep-alive' - }; - - const stream = new ReadableStream({ start: streamEvents }); - return new Response(stream, { headers }); -}; +const credentialsFilePath = './data/youtube_credentials.json'; /** - * Handles YouTube authentication and retrieves user info. + * Handle post requests + * poll, logout, history */ -async function streamEvents(controller: ReadableStreamDefaultController) { - const send = (event: Event) => { - controller?.enqueue(`data: ${JSON.stringify(event)}\n\n`); - }; - - try { - send({ message: 'Loading...' }); +export const POST: RequestHandler = async ({ request }) => { + const response = await request.json(); + const message = response?.message; - youtube = await Innertube.create({ - cache: new UniversalCache(false) - }); + if (message === 'poll') { + // poll + return json(event || {}); - youtube.session.on('auth-pending', (data) => { - send({ - verification_url: data.verification_url, - user_code: data.user_code + // logout + } else if (message === 'logout') { + if (!youtube) { + return json({ + message: 'error', + error: 'YouTube not initialized' }); - }); - - youtube.session.on('auth', async ({ credentials }) => { - await saveAuth(credentials); - }); - - youtube.session.on('update-credentials', async ({ credentials }) => { - await saveAuth(credentials); - }); - - youtube.session.on('auth-error', (error) => { - try { - send({ error: JSON.stringify(error) }); - } catch (err) { - console.error(err); - } - }); - - const auth = await loadAuth(); - await youtube.session.signIn(auth); - - const info = await youtube.account.getInfo(); - send({ data: info }); - controller?.close?.(); - } catch (err) { - send({ error: 'Failed to initialize YouTube session' }); - controller?.close?.(); - } -} - -/** - * Load credentials. - */ -async function loadAuth() { - try { - const data = readFileSync('./data/youtube_credentials.json', 'utf8'); - return JSON.parse(data); - } catch (err) { - // console.error('Failed to load credentials:', err); - } -} - -/** - * Save credentials. - */ -async function saveAuth(credentials: any) { - try { - const data = JSON.stringify(credentials, null, '\t') + '\n'; - writeFileSync('./data/youtube_credentials.json', data); - } catch (err) { - console.error('Failed to save credentials:', err); - } -} - -/** - * Check if a high-resolution YouTube thumbnail is available. - */ -async function getThumbnail(id: string) { - const url = `https://img.youtube.com/vi/${id}/maxresdefault.jpg`; - - // only get headers - const response = await fetch(url, { method: 'HEAD' }); - - if (response.ok) return url; -} - -/** - * POST either `sign-out` or `get-history` - */ -export const POST = async ({ request }) => { - const response = await request.json(); + } - // sign-out - if (response.action === 'sign-out') { try { - if (youtube) { - await youtube.session.signOut(); - unlinkSync('./data/youtube_credentials.json'); - - let config = await loadFile('./data/configuration.yaml'); - - if (config?.addons && config?.addons?.youtube) { - delete config.addons.youtube; - - try { - config = yaml.dump(config); - } catch (err) { - console.log(err); - } - - try { - writeFileSync('./data/configuration.yaml', config); - } catch (err) { - console.log(err); - } - } - - return new Response('Signed out successfully', { status: 200 }); - } else { - return new Response('No active session', { status: 400 }); + await youtube.session.signOut(); + unlinkSync(credentialsFilePath); + const configFilePath = './data/configuration.yaml'; + let config = await loadFile(configFilePath); + + if (config?.addons?.youtube) { + delete config.addons.youtube; + config = yaml.dump(config); + writeFileSync(configFilePath, config); } - } catch (err) { - return error(500, { message: 'Failed to sign out' }); + + return json({ + message: 'success' + }); + } catch (err: any) { + return error(500, err?.message); } - // get-history - } else if (response.action === 'get-history') { + // history + } else if (message === 'history') { try { youtube = await Innertube.create({ cache: new UniversalCache(false) }); - const eventSignal = new Promise((resolve) => { + const events = new Promise((resolve) => { if (!youtube) return; youtube.session.on('auth-pending', () => { @@ -169,13 +66,13 @@ export const POST = async ({ request }) => { resolve(); }); - youtube.session.on('auth', ({ credentials }) => { - saveAuth(credentials); + youtube.session.on('auth', async ({ credentials }) => { + await saveFile(credentials); resolve(); }); - youtube.session.on('update-credentials', ({ credentials }) => { - saveAuth(credentials); + youtube.session.on('update-credentials', async ({ credentials }) => { + await saveFile(credentials); resolve(); }); @@ -185,16 +82,12 @@ export const POST = async ({ request }) => { }); }); - const auth = await loadAuth(); - + const auth = await loadFile(credentialsFilePath); await youtube.session.signIn(auth); - - await eventSignal; + await events; const library = await youtube.getLibrary(); - const history = library?.sections?.find((section: any) => section?.title?.text === 'History'); - const video = history?.contents.find((video) => { return ( video.author?.name === response?.media_artist && @@ -203,6 +96,13 @@ export const POST = async ({ request }) => { }); const { author, title, id, thumbnails } = video; + + const getThumbnail = async (id: string) => { + const url = `https://img.youtube.com/vi/${id}/maxresdefault.jpg`; + const response = await fetch(url, { method: 'HEAD' }); + if (response.ok) return url; + }; + const maxres = await getThumbnail(id); return json({ @@ -211,28 +111,96 @@ export const POST = async ({ request }) => { entity_picture: maxres || thumbnails?.[0]?.url }); } catch (err: any) { - error(503, { message: err.message }); + error(500, err?.message); } } + + return json({ + message: 'error', + error: 'Unhandled post request' + }); }; /** - * Loads a yaml/json file and returns parsed data + * Init auth and return `AccountInfo`. */ -async function loadFile(file: string) { +export const GET: RequestHandler = async () => { try { - const data = readFileSync(file, 'utf8'); + youtube = await Innertube.create({ + cache: new UniversalCache(false) + }); + + youtube.session.on('auth-pending', (data) => { + event = { + message: 'auth-pending', + verification_url: data?.verification_url, + user_code: data?.user_code, + timestamp: new Date().getTime() + }; + }); + + youtube.session.on('auth', async ({ credentials }) => { + event = { message: 'auth' }; + await saveFile(credentials); + }); + + youtube.session.on('update-credentials', async ({ credentials }) => { + event = { message: 'update-credentials' }; + await saveFile(credentials); + }); + + youtube.session.on('auth-error', (error) => { + event = { + message: 'auth-error', + error: error + }; + }); + + const auth = await loadFile(credentialsFilePath); + await youtube.session.signIn(auth); + + const data = await youtube.account.getInfo(); + event = undefined; + return json(data); + + // error + } catch (err: any) { + console.error(err); + return error(500, err.message); + } +}; + +/** + * Load file. + */ +async function loadFile(filePath: string) { + try { + const data = readFileSync(filePath, 'utf8'); + if (!data.trim()) { - return {}; // file is empty, early return object + // file is empty, early return object + return {}; } else { - return file.endsWith('.yaml') ? yaml.load(data) : JSON.parse(data); + return filePath.endsWith('.yaml') ? yaml.load(data) : JSON.parse(data); } - } catch (error) { - if ((error as NodeJS.ErrnoException)?.code === 'ENOENT') { + } catch (err) { + if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') { // console.error(`No existing file found for ${file}`); } else { - console.error(`Error reading or parsing ${file}:`, error); + console.error(`Error reading or parsing ${filePath}:`, err); } return {}; } } + +/** + * Save file. + */ +async function saveFile(credentials: any) { + try { + const data = JSON.stringify(credentials, null, '\t') + '\n'; + writeFileSync(credentialsFilePath, data); + } catch (err) { + console.error('Failed to save credentials:', err); + } +}