From 930165d006c7212063010d91c58cbfa90c6fd00c Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 20 May 2025 19:23:36 -0700 Subject: [PATCH] fix all imports for new structure --- electron-builder.yml | 36 +- electron.vite.config.ts | 36 +- eslint.config.mjs | 1 + package-lock.json | 913 +++++++++++------- package.json | 37 +- src/i18n/i18next-parser.config.js | 2 +- src/main/features/core/lyrics/index.ts | 20 +- src/main/features/core/lyrics/netease.ts | 62 +- src/main/features/core/lyrics/shared.ts | 2 +- src/main/features/core/player/index.ts | 3 +- src/main/features/core/player/media-keys.ts | 1 - src/main/features/core/remote/index.ts | 21 +- src/main/features/core/settings/index.ts | 2 +- src/main/features/index.ts | 3 +- src/main/features/linux/mpris.ts | 7 +- src/main/features/win32/index.ts | 3 - src/main/index.ts | 65 +- src/preload/index.d.ts | 5 + src/preload/local-settings.ts | 2 + src/preload/lyrics.ts | 2 + src/preload/mpris.ts | 2 + src/preload/mpv-player.ts | 2 + src/preload/remote.ts | 3 + src/remote/app.tsx | 10 +- .../components/buttons/image-button.tsx | 3 +- .../components/buttons/reconnect-button.tsx | 5 +- .../components/buttons/remote-button.tsx | 25 +- .../components/buttons/theme-button.tsx | 11 +- src/remote/components/remote-container.tsx | 39 +- src/remote/components/shell.tsx | 5 +- src/remote/components/wrapped-slider.tsx | 59 +- src/remote/index.tsx | 1 + src/remote/service-worker.ts | 3 +- src/remote/store/index.ts | 30 +- src/renderer/api/controller.ts | 7 +- src/renderer/api/jellyfin/jellyfin-api.ts | 7 +- .../api/jellyfin/jellyfin-controller.ts | 19 +- src/renderer/api/navidrome/navidrome-api.ts | 11 +- .../api/navidrome/navidrome-controller.ts | 23 +- src/renderer/api/query-keys.ts | 8 +- src/renderer/api/subsonic/subsonic-api.ts | 4 +- .../api/subsonic/subsonic-controller.ts | 16 +- src/renderer/app.tsx | 33 +- .../components/audio-player/index.tsx | 685 +++++++------ .../audio-player/utils/list-handlers.ts | 2 +- src/renderer/components/button/index.tsx | 6 - src/renderer/components/card/album-card.tsx | 7 +- .../components/card/card-controls.tsx | 6 +- src/renderer/components/card/card-rows.tsx | 4 +- src/renderer/components/card/poster-card.tsx | 6 +- src/renderer/components/date-picker/index.tsx | 5 - .../components/feature-carousel/index.tsx | 6 +- .../components/grid-carousel/index.tsx | 11 +- src/renderer/components/input/index.tsx | 36 - src/renderer/components/modal/index.tsx | 4 - src/renderer/components/page-header/index.tsx | 2 +- .../components/query-builder/index.tsx | 2 +- .../query-builder/query-builder-option.tsx | 2 +- src/renderer/components/rating/index.tsx | 1 - src/renderer/components/scroll-area/index.tsx | 3 +- src/renderer/components/select/index.tsx | 10 - src/renderer/components/separator/index.tsx | 2 +- src/renderer/components/spinner/index.tsx | 10 +- src/renderer/components/text-title/index.tsx | 9 - src/renderer/components/text/index.tsx | 10 - src/renderer/components/tooltip/index.tsx | 7 - .../virtual-grid/grid-card/default-card.tsx | 13 +- .../grid-card/grid-card-controls.tsx | 10 +- .../virtual-grid/grid-card/index.tsx | 6 +- .../virtual-grid/grid-card/poster-card.tsx | 13 +- .../virtual-grid/virtual-grid-wrapper.tsx | 13 +- .../virtual-grid/virtual-infinite-grid.tsx | 12 +- .../virtual-table/cells/album-artist-cell.tsx | 2 +- .../virtual-table/cells/artist-cell.tsx | 2 +- .../cells/combined-title-cell-controls.tsx | 4 +- .../cells/combined-title-cell.tsx | 4 +- .../virtual-table/cells/favorite-cell.tsx | 1 - .../cells/full-width-disc-cell.tsx | 3 +- .../virtual-table/cells/generic-cell.tsx | 4 - .../virtual-table/cells/genre-cell.tsx | 2 +- .../virtual-table/cells/rating-cell.tsx | 1 - .../headers/generic-table-header.tsx | 5 - .../hooks/use-current-song-row-styles.ts | 4 +- .../hooks/use-fixed-table-header.tsx | 2 +- .../virtual-table/hooks/use-virtual-table.ts | 17 +- .../components/virtual-table/index.tsx | 10 +- .../virtual-table/table-config-dropdown.tsx | 2 +- .../virtual-table/table-pagination.tsx | 5 +- src/renderer/context/list-context.tsx | 2 +- .../components/mpv-required.tsx | 5 +- .../components/album-detail-content.tsx | 19 +- .../albums/components/album-detail-header.tsx | 2 +- .../albums/components/album-list-content.tsx | 2 +- .../components/album-list-grid-view.tsx | 18 +- .../components/album-list-header-filters.tsx | 18 +- .../albums/components/album-list-header.tsx | 4 +- .../components/album-list-table-view.tsx | 5 +- .../components/jellyfin-album-filters.tsx | 16 +- .../components/navidrome-album-filters.tsx | 14 +- .../components/subsonic-album-filters.tsx | 7 +- .../albums/queries/album-detail-query.ts | 5 +- .../albums/queries/album-list-count-query.ts | 2 +- .../albums/queries/album-list-query.ts | 2 +- .../albums/routes/album-detail-route.tsx | 2 +- .../albums/routes/album-list-route.tsx | 13 +- .../routes/dummy-album-detail-route.tsx | 2 +- .../album-artist-detail-content.tsx | 20 +- .../components/album-artist-detail-header.tsx | 5 +- ...m-artist-detail-top-songs-list-content.tsx | 5 +- ...um-artist-detail-top-songs-list-header.tsx | 4 +- .../components/album-artist-list-content.tsx | 5 +- .../album-artist-list-grid-view.tsx | 27 +- .../album-artist-list-header-filters.tsx | 21 +- .../components/album-artist-list-header.tsx | 6 +- .../album-artist-list-table-view.tsx | 7 +- .../components/artist-list-content.tsx | 5 +- .../components/artist-list-grid-view.tsx | 28 +- .../components/artist-list-header-filters.tsx | 21 +- .../artists/components/artist-list-header.tsx | 6 +- .../components/artist-list-table-view.tsx | 7 +- .../queries/album-artist-detail-query.ts | 5 +- .../queries/album-artist-list-count-query.ts | 2 +- .../queries/album-artist-list-query.ts | 5 +- .../artists/queries/artist-info-query.ts | 5 +- .../queries/artist-list-count-query.ts | 2 +- .../features/artists/queries/roles-query.ts | 2 +- .../artists/queries/top-songs-list-query.ts | 2 +- .../routes/album-artist-detail-route.tsx | 2 +- ...bum-artist-detail-top-songs-list-route.tsx | 5 +- .../routes/album-artist-list-route.tsx | 7 +- .../artists/routes/artist-list-route.tsx | 7 +- .../context-menu/context-menu-provider.tsx | 13 +- src/renderer/features/context-menu/events.ts | 2 +- .../hooks/use-handle-context-menu.ts | 9 +- .../features/discord-rpc/use-discord-rpc.ts | 4 +- .../genres/components/genre-list-content.tsx | 2 +- .../components/genre-list-grid-view.tsx | 12 +- .../components/genre-list-header-filters.tsx | 18 +- .../genres/components/genre-list-header.tsx | 2 +- .../components/genre-list-table-view.tsx | 2 +- .../genres/queries/genre-list-query.ts | 2 +- .../genres/routes/genre-list-route.tsx | 5 +- .../home/queries/recently-played-query.ts | 2 +- .../features/home/routes/home-route.tsx | 16 +- .../components/item-details-modal.tsx | 18 +- .../lyrics/components/lyrics-search-form.tsx | 9 +- .../features/lyrics/lyrics-actions.tsx | 2 +- src/renderer/features/lyrics/lyrics.tsx | 15 +- .../features/lyrics/queries/lyric-query.ts | 10 +- .../lyrics/queries/lyric-search-query.ts | 4 +- .../features/lyrics/synchronized-lyrics.tsx | 16 +- .../features/lyrics/unsynchronized-lyrics.tsx | 4 +- .../components/drawer-play-queue.tsx | 5 +- .../components/play-queue-list-controls.tsx | 7 +- .../now-playing/components/play-queue.tsx | 7 +- .../components/sidebar-play-queue.tsx | 4 +- .../now-playing/routes/now-playing-route.tsx | 2 +- .../player/components/center-controls.tsx | 9 +- .../components/full-screen-player-image.tsx | 17 +- .../components/full-screen-player-queue.tsx | 2 +- .../player/components/full-screen-player.tsx | 5 +- .../player/components/left-controls.tsx | 2 +- .../player/components/player-button.tsx | 5 - .../features/player/components/playerbar.tsx | 11 +- .../player/components/right-controls.tsx | 7 +- .../player/components/shuffle-all-modal.tsx | 8 +- .../context/play-queue-handler-context.ts | 2 +- .../player/context/webaudio-context.ts | 2 +- .../player/hooks/use-center-controls.ts | 3 +- .../player/hooks/use-handle-playqueue-add.ts | 16 +- .../features/player/hooks/use-scrobble.ts | 4 +- .../player/mutations/scrobble-mutation.ts | 2 +- .../features/player/update-remote-song.tsx | 2 +- src/renderer/features/player/utils.ts | 2 +- .../add-to-playlist-context-modal.tsx | 7 +- .../components/create-playlist-form.tsx | 6 +- .../playlist-detail-song-list-content.tsx | 22 +- ...aylist-detail-song-list-header-filters.tsx | 16 +- .../playlist-detail-song-list-header.tsx | 4 +- .../components/playlist-list-content.tsx | 7 +- .../components/playlist-list-grid-view.tsx | 23 +- .../playlist-list-header-filters.tsx | 14 +- .../components/playlist-list-header.tsx | 2 +- .../components/playlist-list-table-view.tsx | 2 +- .../components/playlist-query-builder.tsx | 28 +- .../components/save-as-playlist-form.tsx | 10 +- .../components/update-playlist-form.tsx | 14 +- .../mutations/add-to-playlist-mutation.ts | 2 +- .../mutations/create-playlist-mutation.ts | 5 +- .../mutations/delete-playlist-mutation.ts | 2 +- .../remove-from-playlist-mutation.ts | 2 +- .../mutations/update-playlist-mutation.ts | 2 +- .../queries/playlist-detail-query.ts | 2 +- .../playlists/queries/playlist-list-query.ts | 2 +- .../queries/playlist-song-list-query.ts | 2 +- .../playlist-detail-song-list-route.tsx | 12 +- .../playlists/routes/playlist-list-route.tsx | 2 +- src/renderer/features/playlists/utils.ts | 4 +- .../search/components/command-palette.tsx | 7 +- .../search/components/home-commands.tsx | 2 +- .../components/library-command-item.tsx | 6 +- .../search/components/search-content.tsx | 5 +- .../search/components/search-header.tsx | 16 +- .../search/components/server-commands.tsx | 2 +- .../features/search/queries/search-query.ts | 2 +- .../servers/components/add-server-form.tsx | 4 +- .../servers/components/edit-server-form.tsx | 2 +- .../servers/components/server-list-item.tsx | 2 +- .../general/application-settings.tsx | 23 +- .../components/general/control-settings.tsx | 2 +- .../components/general/home-settings.tsx | 7 +- .../components/general/sidebar-settings.tsx | 3 +- .../components/general/theme-settings.tsx | 2 +- .../hotkeys/hotkey-manager-settings.tsx | 2 +- .../components/hotkeys/hotkeys-tab.tsx | 3 +- .../hotkeys/window-hotkey-settings.tsx | 6 +- .../components/playback/audio-settings.tsx | 2 +- .../components/playback/lyric-settings.tsx | 2 +- .../components/playback/mpv-settings.tsx | 5 +- .../components/playback/playback-tab.tsx | 2 +- .../components/playback/scrobble-settings.tsx | 6 +- .../playback/transcode-settings.tsx | 6 +- .../settings/components/settings-header.tsx | 3 +- .../settings/components/settings-option.tsx | 5 - .../components/window/password-settings.tsx | 3 +- .../components/window/update-settings.tsx | 3 +- .../components/window/window-settings.tsx | 5 +- .../components/item-image-placeholder.tsx | 2 +- .../shared/components/library-header.tsx | 14 +- .../shared/components/order-toggle-button.tsx | 2 +- .../shared/hooks/use-handle-favorite.ts | 4 +- .../mutations/create-favorite-mutation.ts | 8 +- .../mutations/delete-favorite-mutation.ts | 8 +- .../shared/mutations/set-rating-mutation.ts | 8 +- .../shared/queries/music-folders-query.ts | 5 +- src/renderer/features/shared/utils.ts | 2 +- .../components/share-item-context-modal.tsx | 10 +- .../sharing/mutations/share-item-mutation.ts | 2 +- .../sidebar/components/collapsed-sidebar.tsx | 2 +- .../sidebar/components/sidebar-icon.tsx | 2 +- .../sidebar/components/sidebar-item.tsx | 5 - .../components/sidebar-playlist-list.tsx | 4 +- .../features/sidebar/components/sidebar.tsx | 15 +- .../components/similar-songs-list.tsx | 2 +- .../queries/similar-song-queries.tsx | 2 +- .../components/jellyfin-song-filters.tsx | 2 +- .../components/navidrome-song-filters.tsx | 2 +- .../songs/components/song-list-content.tsx | 2 +- .../songs/components/song-list-grid-view.tsx | 18 +- .../components/song-list-header-filters.tsx | 21 +- .../songs/components/song-list-header.tsx | 4 +- .../songs/components/song-list-table-view.tsx | 2 +- .../songs/components/subsonic-song-filter.tsx | 2 +- .../songs/queries/song-list-count-query.ts | 2 +- .../features/songs/queries/song-list-query.ts | 2 +- .../features/songs/routes/song-list-route.tsx | 6 +- .../features/tag/queries/use-tag-list.ts | 6 +- .../features/titlebar/components/app-menu.tsx | 2 +- .../features/titlebar/components/titlebar.tsx | 6 +- .../features/users/queries/user-list-query.ts | 2 +- .../components/window-controls.tsx | 4 - src/renderer/hooks/use-display-refresh.ts | 2 +- src/renderer/hooks/use-list-filter-refresh.ts | 2 +- .../hooks/use-server-authenticated.ts | 6 +- .../hooks/use-should-pad-titlebar.tsx | 2 +- src/renderer/hooks/use-song-change.ts | 2 +- src/renderer/hooks/use-theme.ts | 2 +- src/renderer/layouts/default-layout.tsx | 6 +- .../layouts/default-layout/right-sidebar.tsx | 2 +- .../default-layout/side-drawer-queue.tsx | 2 +- src/renderer/layouts/window-bar.tsx | 2 +- src/renderer/main.tsx | 2 +- src/renderer/router/app-outlet.tsx | 2 +- src/renderer/router/titlebar-outlet.tsx | 2 +- src/renderer/store/album-artist.store.ts | 4 +- src/renderer/store/app.store.ts | 2 +- src/renderer/store/auth.store.ts | 2 +- src/renderer/store/list.store.ts | 8 +- src/renderer/store/player.store.ts | 32 +- src/renderer/store/playlist.store.ts | 4 +- src/renderer/store/settings.store.ts | 10 +- src/renderer/themes/types.ts | 4 - src/renderer/utils/format.tsx | 2 +- src/renderer/utils/linkify.tsx | 4 +- src/renderer/utils/sanitize.ts | 6 +- .../utils/set-transcoded-queue-data.ts | 4 +- src/shared/api/subsonic/subsonic-normalize.ts | 2 +- src/shared/types/domain-types.ts | 37 +- .../types.ts => shared/types/remote-types.ts} | 112 +-- tsconfig.node.json | 5 +- tsconfig.web.json | 8 +- 291 files changed, 2056 insertions(+), 1894 deletions(-) rename src/{remote/types.ts => shared/types/remote-types.ts} (90%) diff --git a/electron-builder.yml b/electron-builder.yml index 0547af84..20321ca6 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -47,24 +47,24 @@ deb: - libkrb5support.so.0 - libkeyutils.so.1 - libcups.so.2 - rpm: - depends: - - libgssapi_krb5.so.2 - - libavahi-common.so.3 - - libavahi-client.so.3 - - libkrb5.so.3 - - libkrb5support.so.0 - - libkeyutils.so.1 - - libcups.so.2 - freebsd: - depends: - - libgssapi_krb5.so.2 - - libavahi-common.so.3 - - libavahi-client.so.3 - - libkrb5.so.3 - - libkrb5support.so.0 - - libkeyutils.so.1 - - libcups.so.2 +rpm: + depends: + - libgssapi_krb5.so.2 + - libavahi-common.so.3 + - libavahi-client.so.3 + - libkrb5.so.3 + - libkrb5support.so.0 + - libkeyutils.so.1 + - libcups.so.2 +freebsd: + depends: + - libgssapi_krb5.so.2 + - libavahi-common.so.3 + - libavahi-client.so.3 + - libkrb5.so.3 + - libkrb5support.so.0 + - libkeyutils.so.1 + - libcups.so.2 linux: target: - AppImage diff --git a/electron.vite.config.ts b/electron.vite.config.ts index c338aacc..6af18fb4 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,13 +1,41 @@ import react from '@vitejs/plugin-react'; import { externalizeDepsPlugin, UserConfig } from 'electron-vite'; import { resolve } from 'path'; +import conditionalImportPlugin from 'vite-plugin-conditional-import'; +import dynamicImportPlugin from 'vite-plugin-dynamic-import'; + +const currentOSEnv = process.platform; const config: UserConfig = { main: { - plugins: [externalizeDepsPlugin()], + define: { + 'import.meta.env.IS_LINUX': JSON.stringify(currentOSEnv === 'linux'), + 'import.meta.env.IS_MACOS': JSON.stringify(currentOSEnv === 'darwin'), + 'import.meta.env.IS_WIN': JSON.stringify(currentOSEnv === 'win32'), + }, + plugins: [ + externalizeDepsPlugin(), + dynamicImportPlugin(), + conditionalImportPlugin({ + currentEnv: currentOSEnv, + envs: ['win32', 'linux', 'darwin'], + }), + ], + resolve: { + alias: { + '/@/main': resolve('src/main'), + '/@/shared': resolve('src/shared'), + }, + }, }, preload: { plugins: [externalizeDepsPlugin()], + resolve: { + alias: { + '/@/preload': resolve('src/preload'), + '/@/shared': resolve('src/shared'), + }, + }, }, renderer: { css: { @@ -20,12 +48,8 @@ const config: UserConfig = { resolve: { alias: { '/@/i18n': resolve('src/i18n'), - '/@/main': resolve('src/main'), + '/@/remote': resolve('src/remote'), '/@/renderer': resolve('src/renderer'), - '/@/renderer/api': resolve('src/renderer/api'), - '/@/renderer/components': resolve('src/renderer/components'), - '/@/renderer/features': resolve('src/renderer/features'), - '/@/renderer/hooks': resolve('src/renderer/hooks'), '/@/shared': resolve('src/shared'), }, }, diff --git a/eslint.config.mjs b/eslint.config.mjs index ef8cbcb3..04a62ef9 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -43,6 +43,7 @@ export default tseslint.config( 'no-unused-vars': 'off', 'no-use-before-define': 'off', quotes: ['error', 'single'], + 'react-refresh/only-export-components': 'off', 'react/display-name': 'off', semi: ['error', 'always'], }, diff --git a/package-lock.json b/package-lock.json index 9bf65edf..ff38d820 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,29 +1,26 @@ { "name": "feishin", - "version": "0.13.0", - "lockfileVersion": 2, + "version": "0.12.7", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "feishin", - "version": "0.13.0", - "hasInstallScript": true, - "dependencies": { + "version": "0.12.7", "@ag-grid-community/client-side-row-model": "^28.2.1", - "@ag-grid-community/core": "^28.2.1", "@ag-grid-community/infinite-row-model": "^28.2.1", "@ag-grid-community/react": "^28.2.1", "@ag-grid-community/styles": "^28.2.1", "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^4.0.0", "@emotion/react": "^11.10.4", - "@mantine/core": "^6.0.17", - "@mantine/dates": "^6.0.17", - "@mantine/form": "^6.0.17", - "@mantine/hooks": "^6.0.17", - "@mantine/modals": "^6.0.17", - "@mantine/notifications": "^6.0.17", - "@mantine/utils": "^6.0.17", + "@mantine/core": "^6.0.21", + "@mantine/dates": "^6.0.21", + "@mantine/form": "^6.0.21", + "@mantine/hooks": "^6.0.21", + "@mantine/modals": "^6.0.21", + "@mantine/notifications": "^6.0.21", + "@mantine/utils": "^6.0.21", "@tanstack/react-query": "^4.32.1", "@tanstack/react-query-devtools": "^4.32.1", "@tanstack/react-query-persist-client": "^4.32.1", @@ -101,6 +98,7 @@ "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-window": "^1.8.5", "@types/react-window-infinite-loader": "^1.0.6", + "@types/source-map-support": "^0.5.10", "@types/styled-components": "^5.1.26", "@types/terser-webpack-plugin": "^5.0.4", "@types/webpack-bundle-analyzer": "^4.4.1", @@ -117,7 +115,7 @@ "css-minimizer-webpack-plugin": "^3.4.1", "detect-port": "^1.3.0", "electron": "^35.1.5", - "electron-builder": "^25.1.8", + "electron-builder": "^26.0.12", "electron-devtools-installer": "^3.2.0", "electron-notarize": "^1.2.1", "electron-vite": "^3.1.0", @@ -177,6 +175,8 @@ "typescript-plugin-styled-components": "^3.0.0", "url-loader": "^4.1.1", "vite": "^6.2.6", + "vite-plugin-conditional-import": "^0.1.7", + "vite-plugin-dynamic-import": "^1.6.0", "webpack": "^5.94.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.2", @@ -1073,9 +1073,9 @@ } }, "node_modules/@electron/asar": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", - "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "version": "3.2.18", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.18.tgz", + "integrity": "sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==", "dev": true, "license": "MIT", "dependencies": { @@ -1136,11 +1136,41 @@ "node": "*" } }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@electron/get": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.1", @@ -1162,7 +1192,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -1177,7 +1206,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" @@ -1187,7 +1215,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1197,7 +1224,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4.0.0" @@ -1373,6 +1399,45 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", @@ -3652,6 +3717,18 @@ "react": "^16.8 || ^17.0 || ^18.0" } }, + "node_modules/@radix-ui/react-dialog/node_modules/@types/react": { + "version": "18.3.22", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.22.tgz", + "integrity": "sha512-vUhG0YmQZ7kL/tmKLrD3g5zXbXXreZXB3pmROW8bg3CnLnpjkRVwUlLne7Ufa2r9yJ8+/6B73RzhAek5TBKh2Q==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz", @@ -4277,7 +4354,6 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -4325,7 +4401,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, "license": "MIT", "dependencies": { "defer-to-connect": "^2.0.0" @@ -4617,6 +4692,18 @@ "react-dom": "^18.0.0" } }, + "node_modules/@testing-library/react/node_modules/@types/react": { + "version": "18.3.22", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.22.tgz", + "integrity": "sha512-vUhG0YmQZ7kL/tmKLrD3g5zXbXXreZXB3pmROW8bg3CnLnpjkRVwUlLne7Ufa2r9yJ8+/6B73RzhAek5TBKh2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@testing-library/react/node_modules/@types/react-dom": { "version": "18.3.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", @@ -4770,7 +4857,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, "license": "MIT", "dependencies": { "@types/http-cache-semantics": "*", @@ -4940,7 +5026,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true, "license": "MIT" }, "node_modules/@types/http-errors": { @@ -5016,7 +5101,6 @@ "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -5068,7 +5152,6 @@ "version": "22.15.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.18.tgz", "integrity": "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5120,7 +5203,7 @@ "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/qs": { @@ -5141,7 +5224,7 @@ "version": "19.1.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.4.tgz", "integrity": "sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -5214,7 +5297,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -5284,6 +5366,26 @@ "@types/node": "*" } }, + "node_modules/@types/source-map-support": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-tgVP2H469x9zq34Z0m/fgPewGhg/MLClalNOiPIzQlXrSS2YrKu/xCdSCKnEDwkFha51VKEKB6A9wW26/ZNwzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "^0.6.0" + } + }, + "node_modules/@types/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -5402,7 +5504,6 @@ "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -6221,39 +6322,52 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", - "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", + "version": "5.0.0-alpha.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", "dev": true, "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.1.8.tgz", - "integrity": "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg==", + "version": "26.0.12", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.0.12.tgz", + "integrity": "sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==", "dev": true, "license": "MIT", "dependencies": { "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.2.18", + "@electron/fuses": "^1.8.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", + "@electron/rebuild": "3.7.0", "@electron/universal": "2.0.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "builder-util": "26.0.11", + "builder-util-runtime": "9.3.1", "chromium-pickle-js": "^0.2.0", "config-file-ts": "0.2.8-rc1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "25.1.7", - "form-data": "^4.0.0", + "electron-publish": "26.0.11", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", @@ -6262,27 +6376,29 @@ "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.0", + "plist": "3.1.0", "resedit": "^1.7.0", - "sanitize-filename": "^1.6.3", "semver": "^7.3.8", "tar": "^6.1.12", - "temp-file": "^3.4.0" + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "25.1.8", - "electron-builder-squirrel-windows": "25.1.8" + "dmg-builder": "26.0.12", + "electron-builder-squirrel-windows": "26.0.12" } }, "node_modules/app-builder-lib/node_modules/@electron/rebuild": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz", - "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.7.0.tgz", + "integrity": "sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==", "dev": true, "license": "MIT", "dependencies": { + "@electron/node-gyp": "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.1.1", @@ -6291,7 +6407,6 @@ "got": "^11.7.0", "node-abi": "^3.45.0", "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", @@ -6305,28 +6420,6 @@ "node": ">=12.13.0" } }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -6914,23 +7007,6 @@ "readable-stream": "^3.4.0" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/bluebird-lst": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", - "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.5" - } - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -7008,7 +7084,6 @@ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, "license": "MIT", "optional": true }, @@ -7230,7 +7305,6 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -7243,35 +7317,35 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.1.7.tgz", - "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", + "version": "26.0.11", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.0.11.tgz", + "integrity": "sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==", "dev": true, "license": "MIT", "dependencies": { "@types/debug": "^4.1.6", "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", + "app-builder-bin": "5.0.0-alpha.12", + "builder-util-runtime": "9.3.1", "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", + "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", - "temp-file": "^3.4.0" + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" } }, "node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "dev": true, + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz", + "integrity": "sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==", "license": "MIT", "dependencies": { "debug": "^4.3.4", @@ -7345,7 +7419,6 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.6.0" @@ -7355,7 +7428,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, "license": "MIT", "dependencies": { "clone-response": "^1.0.2", @@ -7811,7 +7883,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, "license": "MIT", "dependencies": { "mimic-response": "^1.0.0" @@ -7887,16 +7958,6 @@ "dev": true, "license": "MIT" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -8188,13 +8249,6 @@ "node": ">=0.8" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -8303,6 +8357,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/crc": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", @@ -8321,6 +8384,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -8690,6 +8762,16 @@ "postcss": "^8.2.15" } }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/csso": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", @@ -8991,7 +9073,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" @@ -9007,7 +9088,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9099,7 +9179,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9158,13 +9237,6 @@ "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "license": "MIT" - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9210,7 +9282,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/detect-node-es": { @@ -9312,15 +9384,15 @@ "license": "MIT" }, "node_modules/dmg-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.1.8.tgz", - "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", + "version": "26.0.12", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.0.12.tgz", + "integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "26.0.12", + "builder-util": "26.0.11", + "builder-util-runtime": "9.3.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -9606,7 +9678,6 @@ "version": "35.4.0", "resolved": "https://registry.npmjs.org/electron/-/electron-35.4.0.tgz", "integrity": "sha512-VIPSNcUnic00aaE83w6BW4Dj1kE8A5DU0nVbvwqotN3+gseGunbP4WyHp/kfKXVKQj1S3No3HnYxU5LJmYbAtw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -9622,17 +9693,17 @@ } }, "node_modules/electron-builder": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.1.8.tgz", - "integrity": "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig==", + "version": "26.0.12", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.0.12.tgz", + "integrity": "sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "app-builder-lib": "26.0.12", + "builder-util": "26.0.11", + "builder-util-runtime": "9.3.1", "chalk": "^4.1.2", - "dmg-builder": "25.1.8", + "dmg-builder": "26.0.12", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", @@ -9647,6 +9718,19 @@ "node": ">=14.0.0" } }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.0.12", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.0.12.tgz", + "integrity": "sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.0.12", + "builder-util": "26.0.11", + "electron-winstaller": "5.4.0" + } + }, "node_modules/electron-debug": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/electron-debug/-/electron-debug-3.2.0.tgz", @@ -9738,16 +9822,17 @@ } }, "node_modules/electron-publish": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz", - "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", + "version": "26.0.11", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.0.11.tgz", + "integrity": "sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", + "builder-util": "26.0.11", + "builder-util-runtime": "9.3.1", "chalk": "^4.1.2", + "form-data": "^4.0.0", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" @@ -9789,19 +9874,6 @@ "tiny-typed-emitter": "^2.1.0" } }, - "node_modules/electron-updater/node_modules/builder-util-runtime": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz", - "integrity": "sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/electron-vite": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-3.1.0.tgz", @@ -9832,6 +9904,66 @@ } } }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron-winstaller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-winstaller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/electronmon": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/electronmon/-/electronmon-2.0.3.tgz", @@ -9933,7 +10065,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -10239,7 +10370,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, "license": "MIT", "optional": true }, @@ -12023,7 +12153,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -12187,7 +12316,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" @@ -12699,27 +12827,6 @@ "node": ">=10" } }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -12800,7 +12907,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -12921,7 +13027,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, "license": "BSD-3-Clause", "optional": true, "dependencies": { @@ -12994,7 +13099,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -13051,7 +13156,6 @@ "version": "11.8.6", "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -13224,13 +13328,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -13581,7 +13678,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { @@ -13686,7 +13782,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, "license": "MIT", "dependencies": { "quick-lru": "^5.1.1", @@ -15657,6 +15752,19 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-validate": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", @@ -15948,7 +16056,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -15988,7 +16095,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, "license": "ISC", "optional": true }, @@ -16102,7 +16208,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -16413,6 +16518,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/listr2": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", @@ -16643,7 +16758,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16830,7 +16944,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -17089,6 +17202,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -17136,7 +17262,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -17602,78 +17727,6 @@ "node": ">= 6.13.0" } }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -17739,7 +17792,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -17774,23 +17826,6 @@ "node": ">=8" } }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -17981,7 +18016,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -18119,7 +18153,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -18455,7 +18488,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -18465,13 +18497,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -19359,6 +19391,36 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -19465,7 +19527,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -19574,7 +19635,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -19639,7 +19699,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -19773,7 +19832,6 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19783,7 +19841,6 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", - "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.26.0" @@ -20523,7 +20580,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true, "license": "MIT" }, "node_modules/resolve-cwd": { @@ -20595,7 +20651,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, "license": "MIT", "dependencies": { "lowercase-keys": "^2.0.0" @@ -20713,7 +20768,6 @@ "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, "license": "BSD-3-Clause", "optional": true, "dependencies": { @@ -21397,7 +21451,6 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "dev": true, "license": "MIT" }, "node_modules/schema-utils": { @@ -21456,7 +21509,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, "license": "MIT", "optional": true }, @@ -21529,7 +21581,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -21546,7 +21597,6 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "optional": true, "engines": { @@ -21668,13 +21718,6 @@ "node": ">= 0.8.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -22143,7 +22186,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause" }, "node_modules/ssr-window": { @@ -23050,7 +23093,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "debug": "^4.1.0" @@ -23450,6 +23492,21 @@ "streamx": "^2.12.5" } }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/temp-file": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", @@ -23461,6 +23518,84 @@ "fs-extra": "^10.0.0" } }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -23752,6 +23887,26 @@ "dev": true, "license": "MIT" }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/tiny-typed-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", @@ -23775,19 +23930,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -40816,7 +40958,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/unique-filename": { @@ -41413,17 +41554,48 @@ } } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/vite-plugin-conditional-import": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/vite-plugin-conditional-import/-/vite-plugin-conditional-import-0.1.7.tgz", + "integrity": "sha512-q1galZvTv2K0Sjo+41AlXIatqA5ai6njfU+vO4Gn399c5Q7skvNU250J5baQDNdRL6iOMl+IgfYGNMYN1n2rSA==", "dev": true, "license": "MIT", + "dependencies": { + "es-module-lexer": "1.5.0", + "magic-string": "0.30.9" + } + }, + "node_modules/vite-plugin-conditional-import/node_modules/es-module-lexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-plugin-conditional-import/node_modules/magic-string": { + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vite-plugin-dynamic-import": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-plugin-dynamic-import/-/vite-plugin-dynamic-import-1.6.0.tgz", + "integrity": "sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.12.1", + "es-module-lexer": "^1.5.4", + "fast-glob": "^3.3.2", + "magic-string": "^0.30.11" } }, "node_modules/void-elements": { @@ -41973,6 +42145,19 @@ "dev": true, "license": "MIT" }, + "node_modules/webpack-dev-server/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/webpack-dev-server/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -42268,16 +42453,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -42336,7 +42511,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -42454,12 +42628,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" } }, "node_modules/yargs": { @@ -42505,7 +42685,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", diff --git a/package.json b/package.json index c7599de8..468ff41f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "feishin", "productName": "Feishin", "version": "0.12.7", - "description": "", + "description": "A modern self-hosted music player.", "main": "./out/main/index.js", "homepage": "https://github.com/jeffvli/feishin", "scripts": { @@ -32,13 +32,13 @@ "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^4.0.0", "@emotion/react": "^11.10.4", - "@mantine/core": "^6.0.17", - "@mantine/dates": "^6.0.17", - "@mantine/form": "^6.0.17", - "@mantine/hooks": "^6.0.17", - "@mantine/modals": "^6.0.17", - "@mantine/notifications": "^6.0.17", - "@mantine/utils": "^6.0.17", + "@mantine/core": "^6.0.21", + "@mantine/dates": "^6.0.21", + "@mantine/form": "^6.0.21", + "@mantine/hooks": "^6.0.21", + "@mantine/modals": "^6.0.21", + "@mantine/notifications": "^6.0.21", + "@mantine/utils": "^6.0.21", "@tanstack/react-query": "^4.32.1", "@tanstack/react-query-devtools": "^4.32.1", "@tanstack/react-query-persist-client": "^4.32.1", @@ -116,6 +116,7 @@ "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-window": "^1.8.5", "@types/react-window-infinite-loader": "^1.0.6", + "@types/source-map-support": "^0.5.10", "@types/styled-components": "^5.1.26", "@types/terser-webpack-plugin": "^5.0.4", "@types/webpack-bundle-analyzer": "^4.4.1", @@ -132,7 +133,7 @@ "css-minimizer-webpack-plugin": "^3.4.1", "detect-port": "^1.3.0", "electron": "^35.1.5", - "electron-builder": "^25.1.8", + "electron-builder": "^26.0.12", "electron-devtools-installer": "^3.2.0", "electron-notarize": "^1.2.1", "electron-vite": "^3.1.0", @@ -192,10 +193,28 @@ "typescript-plugin-styled-components": "^3.0.0", "url-loader": "^4.1.1", "vite": "^6.2.6", + "vite-plugin-conditional-import": "^0.1.7", + "vite-plugin-dynamic-import": "^1.6.0", "webpack": "^5.94.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.8.0", "webpack-merge": "^5.8.0" + }, + "keywords": [ + "subsonic", + "navidrome", + "airsonic", + "jellyfin", + "react", + "electron" + ], + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/jeffvli/feishin/issues" + }, + "author": { + "name": "jeffvli", + "url": "https://github.com/jeffvli/" } } diff --git a/src/i18n/i18next-parser.config.js b/src/i18n/i18next-parser.config.js index 3f4665ee..44c1a5e7 100644 --- a/src/i18n/i18next-parser.config.js +++ b/src/i18n/i18next-parser.config.js @@ -5,7 +5,7 @@ module.exports = { createOldCatalogs: true, customValueTemplate: null, defaultNamespace: 'translation', - defaultValue: function (locale, namespace, key, value) { + defaultValue: function (locale, namespace, key) { return key; }, failOnUpdate: false, diff --git a/src/main/features/core/lyrics/index.ts b/src/main/features/core/lyrics/index.ts index a4b72c6d..ab38c8b2 100644 --- a/src/main/features/core/lyrics/index.ts +++ b/src/main/features/core/lyrics/index.ts @@ -1,6 +1,6 @@ import { ipcMain } from 'electron'; -import { store } from '../settings/index'; +import { store } from '../settings'; import { getLyricsBySongId as getGenius, query as queryGenius, @@ -17,6 +17,8 @@ import { getSearchResults as searchNetease, } from './netease'; +import { Song } from '/@/shared/types/domain-types'; + export enum LyricSource { GENIUS = 'Genius', LRCLIB = 'lrclib.net', @@ -94,10 +96,10 @@ const MAX_CACHED_ITEMS = 10; const lyricCache = new Map(); -const getRemoteLyrics = async (song: any) => { +const getRemoteLyrics = async (song: Song) => { const sources = store.get('lyrics', []) as LyricSource[]; - const cached = lyricCache.get(song.id); + const cached = lyricCache.get(song.id.toString()); if (cached) { for (const source of sources) { @@ -106,16 +108,16 @@ const getRemoteLyrics = async (song: any) => { } } - let lyricsFromSource = null; + let lyricsFromSource: InternetProviderLyricResponse | null = null; for (const source of sources) { const params = { album: song.album || song.name, - artist: song.artistName, + artist: song.artists[0].name, duration: song.duration / 1000.0, name: song.name, }; - const response = await FETCHERS[source](params); + const response = await FETCHERS[source](params as unknown as LyricSearchQuery); if (response) { const newResult = cached @@ -127,10 +129,12 @@ const getRemoteLyrics = async (song: any) => { if (lyricCache.size === MAX_CACHED_ITEMS && cached === undefined) { const toRemove = lyricCache.keys().next().value; - lyricCache.delete(toRemove); + if (toRemove) { + lyricCache.delete(toRemove); + } } - lyricCache.set(song.id, newResult); + lyricCache.set(song.id.toString(), newResult); lyricsFromSource = response; break; diff --git a/src/main/features/core/lyrics/netease.ts b/src/main/features/core/lyrics/netease.ts index d59f9faf..bf702e5b 100644 --- a/src/main/features/core/lyrics/netease.ts +++ b/src/main/features/core/lyrics/netease.ts @@ -13,37 +13,6 @@ const LYRICS_URL = 'https://music.163.com/api/song/lyric'; // Adapted from https://github.com/NyaomiDEV/Sunamu/blob/master/src/main/lyricproviders/netease.ts -export interface Album { - artist: Artist; - copyrightId: number; - id: number; - mark: number; - name: string; - picId: number; - publishTime: number; - size: number; - status: number; - transNames?: string[]; -} - -export interface Artist { - albumSize: number; - alias: any[]; - fansGroup: null; - id: number; - img1v1: number; - img1v1Url: string; - name: string; - picId: number; - picUrl: null; - trans: null; -} - -export interface NetEaseResponse { - code: number; - result: Result; -} - export interface Result { hasMore: boolean; songCount: number; @@ -68,6 +37,37 @@ export interface Song { transNames?: string[]; } +interface Album { + artist: Artist; + copyrightId: number; + id: number; + mark: number; + name: string; + picId: number; + publishTime: number; + size: number; + status: number; + transNames?: string[]; +} + +interface Artist { + albumSize: number; + alias: any[]; + fansGroup: null; + id: number; + img1v1: number; + img1v1Url: string; + name: string; + picId: number; + picUrl: null; + trans: null; +} + +interface NetEaseResponse { + code: number; + result: Result; +} + export async function getLyricsBySongId(songId: string): Promise { let result: AxiosResponse; try { diff --git a/src/main/features/core/lyrics/shared.ts b/src/main/features/core/lyrics/shared.ts index 44dc4853..190aabc2 100644 --- a/src/main/features/core/lyrics/shared.ts +++ b/src/main/features/core/lyrics/shared.ts @@ -3,7 +3,7 @@ import Fuse from 'fuse.js'; import { InternetProviderLyricSearchResponse, LyricSearchQuery, -} from '../../../../renderer/api/types'; +} from '/@/shared/types/domain-types'; export const orderSearchResults = (args: { params: LyricSearchQuery; diff --git a/src/main/features/core/player/index.ts b/src/main/features/core/player/index.ts index b0e88582..dc8dc513 100644 --- a/src/main/features/core/player/index.ts +++ b/src/main/features/core/player/index.ts @@ -330,7 +330,8 @@ ipcMain.on('player-set-queue', async (_event, current?: string, next?: string, p if (current) { try { await getMpvInstance()?.load(current, 'replace'); - } catch (error) { + } catch (error: any | NodeMpvError) { + mpvLog({ action: `Failed to load current song` }, error); await getMpvInstance()?.play(); } diff --git a/src/main/features/core/player/media-keys.ts b/src/main/features/core/player/media-keys.ts index e919fb29..dfed0c88 100644 --- a/src/main/features/core/player/media-keys.ts +++ b/src/main/features/core/player/media-keys.ts @@ -1,4 +1,3 @@ -/* eslint-disable promise/always-return */ import { BrowserWindow, globalShortcut, systemPreferences } from 'electron'; import { isMacOS } from '../../../utils'; diff --git a/src/main/features/core/remote/index.ts b/src/main/features/core/remote/index.ts index 9fd0a686..1405b4e8 100644 --- a/src/main/features/core/remote/index.ts +++ b/src/main/features/core/remote/index.ts @@ -7,16 +7,25 @@ import { join } from 'path'; import { WebSocket, WebSocketServer, Server as WsServer } from 'ws'; import { deflate, gzip } from 'zlib'; -import { getMainWindow } from '../../..'; -import { isLinux } from '../../../utils'; import manifest from './manifest.json'; +import { getMainWindow } from '/@/main/index'; +import { isLinux } from '/@/main/utils'; +import { QueueSong } from '/@/shared/types/domain-types'; +import { ClientEvent, ServerEvent } from '/@/shared/types/remote-types'; +import { PlayerRepeat, PlayerStatus, SongState } from '/@/shared/types/types'; + let mprisPlayer: any | undefined; -if (isLinux()) { - mprisPlayer = require('../../linux/mpris').mprisPlayer; +async function initMpris() { + if (isLinux()) { + const mpris = await import('../../linux/mpris'); + mprisPlayer = mpris.mprisPlayer; + } } +initMpris(); + interface MimeType { css: string; html: string; @@ -630,8 +639,8 @@ if (mprisPlayer) { mprisPlayer.on('loopStatus', (event: string) => { const repeat = event === 'Playlist' ? 'all' : event === 'Track' ? 'one' : 'none'; - currentState.repeat = repeat; - broadcast({ data: repeat, event: 'repeat' }); + currentState.repeat = repeat as PlayerRepeat; + broadcast({ data: repeat, event: 'repeat' } as ServerEvent); }); mprisPlayer.on('shuffle', (shuffle: boolean) => { diff --git a/src/main/features/core/settings/index.ts b/src/main/features/core/settings/index.ts index 05cd0ad3..beb5b4c1 100644 --- a/src/main/features/core/settings/index.ts +++ b/src/main/features/core/settings/index.ts @@ -1,4 +1,4 @@ -import type { TitleTheme } from '/@/renderer/types'; +import type { TitleTheme } from '/@/shared/types/types'; import { ipcMain, nativeTheme, safeStorage } from 'electron'; import Store from 'electron-store'; diff --git a/src/main/features/index.ts b/src/main/features/index.ts index b80182ff..23184e54 100644 --- a/src/main/features/index.ts +++ b/src/main/features/index.ts @@ -1,3 +1,2 @@ import './core'; - -// require(`./${process.platform}`) +import(`./${process.platform}`); diff --git a/src/main/features/linux/mpris.ts b/src/main/features/linux/mpris.ts index f53eeb8d..dd57a389 100644 --- a/src/main/features/linux/mpris.ts +++ b/src/main/features/linux/mpris.ts @@ -1,10 +1,9 @@ import { ipcMain } from 'electron'; import Player from 'mpris-service'; -import { PlayerRepeat, PlayerStatus } from '../../../renderer/types'; -import { getMainWindow } from '../../main'; - -import { QueueSong } from '/@/renderer/api/types'; +import { getMainWindow } from '/@/main/index'; +import { QueueSong } from '/@/shared/types/domain-types'; +import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types'; const mprisPlayer = Player({ identity: 'Feishin', diff --git a/src/main/features/win32/index.ts b/src/main/features/win32/index.ts index 1b7c8727..e69de29b 100644 --- a/src/main/features/win32/index.ts +++ b/src/main/features/win32/index.ts @@ -1,3 +0,0 @@ -// Dummy file to satisfy the build system - -export {}; diff --git a/src/main/index.ts b/src/main/index.ts index ed679488..4667bb3d 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,5 +1,4 @@ -import { electronApp, is, optimizer } from '@electron-toolkit/utils'; -import { constants } from 'buffer'; +import { is } from '@electron-toolkit/utils'; import { app, BrowserWindow, @@ -19,7 +18,7 @@ import { import electronLocalShortcut from 'electron-localshortcut'; import log from 'electron-log/main'; import { autoUpdater } from 'electron-updater'; -import { access, readFile, writeFile } from 'fs'; +import { access, constants, readFile, writeFile } from 'fs'; import path, { join } from 'path'; import { deflate, inflate } from 'zlib'; @@ -36,6 +35,8 @@ import { } from './utils'; import './features'; +import { TitleTheme } from '/@/shared/types/types'; + export default class AppUpdater { constructor() { log.transports.file.level = 'info'; @@ -66,27 +67,31 @@ let exitFromTray = false; let forceQuit = false; if (process.env.NODE_ENV === 'production') { - const sourceMapSupport = require('source-map-support'); - sourceMapSupport.install(); + import('source-map-support').then((sourceMapSupport) => { + sourceMapSupport.install(); + }); } const isDevelopment = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; if (isDevelopment) { - require('electron-debug')(); + import('electron-debug').then((electronDebug) => { + electronDebug.default(); + }); } const installExtensions = async () => { - const installer = require('electron-devtools-installer'); - const forceDownload = !!process.env.UPGRADE_EXTENSIONS; - const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS']; + import('electron-devtools-installer').then((installer) => { + const forceDownload = !!process.env.UPGRADE_EXTENSIONS; + const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS']; - return installer - .default( - extensions.map((name) => installer[name]), - forceDownload, - ) - .catch(console.log); + return installer + .default( + extensions.map((name) => installer[name]), + forceDownload, + ) + .catch(console.log); + }); }; const RESOURCES_PATH = app.isPackaged @@ -393,7 +398,7 @@ async function createWindow(first = true): Promise { mainWindow = null; }); - const saved = false; + let saved = false; mainWindow.on('close', (event) => { store.set('bounds', mainWindow?.getNormalBounds()); @@ -446,7 +451,7 @@ async function createWindow(first = true): Promise { } }); - mainWindow.on('minimize', (event: any) => { + (mainWindow as any).on('minimize', (event: any) => { if (store.get('window_minimize_to_tray') === true) { event.preventDefault(); mainWindow?.hide(); @@ -632,22 +637,22 @@ if (!singleInstance) { app.whenReady() .then(() => { - // protocol.handle('feishin', async (request) => { - // const filePath = `file://${request.url.slice('feishin://'.length)}` - // const response = await net.fetch(filePath) - // const contentType = response.headers.get('content-type') + protocol.handle('feishin', async (request) => { + const filePath = `file://${request.url.slice('feishin://'.length)}`; + const response = await net.fetch(filePath); + const contentType = response.headers.get('content-type'); - // if (!contentType || !FONT_HEADERS.includes(contentType)) { - // getMainWindow()?.webContents.send('custom-font-error', filePath) + if (!contentType || !FONT_HEADERS.includes(contentType)) { + getMainWindow()?.webContents.send('custom-font-error', filePath); - // return new Response(null, { - // status: 403, - // statusText: 'Forbidden' - // }) - // } + return new Response(null, { + status: 403, + statusText: 'Forbidden', + }); + } - // return response - // }) + return response; + }); createWindow(); if (store.get('window_enable_tray', true)) { diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index caecdb7b..1c7de78c 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -6,5 +6,10 @@ declare global { interface Window { api: PreloadApi; electron: ElectronAPI; + queryLocalFonts?: () => Promise; + SERVER_LOCK?: boolean; + SERVER_NAME?: string; + SERVER_TYPE?: ServerType; + SERVER_URL?: string; } } diff --git a/src/preload/local-settings.ts b/src/preload/local-settings.ts index 986f5203..23969702 100644 --- a/src/preload/local-settings.ts +++ b/src/preload/local-settings.ts @@ -1,6 +1,8 @@ import { ipcRenderer, IpcRendererEvent, webFrame } from 'electron'; import Store from 'electron-store'; +import { TitleTheme } from '/@/shared/types/types'; + const store = new Store(); const set = ( diff --git a/src/preload/lyrics.ts b/src/preload/lyrics.ts index 3c0cbb75..b69ab384 100644 --- a/src/preload/lyrics.ts +++ b/src/preload/lyrics.ts @@ -7,6 +7,8 @@ import { LyricSource, } from '../main/features/core/lyrics'; +import { QueueSong } from '/@/shared/types/domain-types'; + const getRemoteLyricsBySong = (song: QueueSong) => { const result = ipcRenderer.invoke('lyric-by-song', song); return result; diff --git a/src/preload/mpris.ts b/src/preload/mpris.ts index 0edb90c3..4d860220 100644 --- a/src/preload/mpris.ts +++ b/src/preload/mpris.ts @@ -1,5 +1,7 @@ import { ipcRenderer, IpcRendererEvent } from 'electron'; +import { PlayerRepeat } from '/@/shared/types/types'; + const updatePosition = (timeSec: number) => { ipcRenderer.send('mpris-update-position', timeSec); }; diff --git a/src/preload/mpv-player.ts b/src/preload/mpv-player.ts index 8370db3c..b393fca5 100644 --- a/src/preload/mpv-player.ts +++ b/src/preload/mpv-player.ts @@ -1,5 +1,7 @@ import { ipcRenderer, IpcRendererEvent } from 'electron'; +import { PlayerData } from '/@/shared/types/domain-types'; + const initialize = (data: { extraParameters?: string[]; properties?: Record }) => { return ipcRenderer.invoke('player-initialize', data); }; diff --git a/src/preload/remote.ts b/src/preload/remote.ts index 95f3849f..dd5f348e 100644 --- a/src/preload/remote.ts +++ b/src/preload/remote.ts @@ -1,5 +1,8 @@ import { ipcRenderer, IpcRendererEvent } from 'electron'; +import { QueueSong } from '/@/shared/types/domain-types'; +import { PlayerStatus } from '/@/shared/types/types'; + const requestFavorite = ( cb: ( event: IpcRendererEvent, diff --git a/src/remote/app.tsx b/src/remote/app.tsx index d5581430..db16ca3e 100644 --- a/src/remote/app.tsx +++ b/src/remote/app.tsx @@ -1,8 +1,10 @@ -import { useEffect } from 'react'; import { MantineProvider } from '@mantine/core'; +import { useEffect } from 'react'; + import './styles/global.scss'; -import { useIsDark, useReconnect } from '/@/remote/store'; + import { Shell } from '/@/remote/components/shell'; +import { useIsDark, useReconnect } from '/@/remote/store'; export const App = () => { const isDark = useIsDark(); @@ -14,8 +16,6 @@ export const App = () => { return ( { xs: '0rem', }, }} + withGlobalStyles + withNormalizeCSS > diff --git a/src/remote/components/buttons/image-button.tsx b/src/remote/components/buttons/image-button.tsx index 9aabd215..04837607 100644 --- a/src/remote/components/buttons/image-button.tsx +++ b/src/remote/components/buttons/image-button.tsx @@ -1,4 +1,5 @@ import { CiImageOff, CiImageOn } from 'react-icons/ci'; + import { RemoteButton } from '/@/remote/components/buttons/remote-button'; import { useShowImage, useToggleShowImage } from '/@/remote/store'; @@ -9,10 +10,10 @@ export const ImageButton = () => { return ( toggleImage()} size="xl" tooltip={showImage ? 'Hide Image' : 'Show Image'} variant="default" - onClick={() => toggleImage()} > {showImage ? : } diff --git a/src/remote/components/buttons/reconnect-button.tsx b/src/remote/components/buttons/reconnect-button.tsx index 41b5ed20..97ff42f2 100644 --- a/src/remote/components/buttons/reconnect-button.tsx +++ b/src/remote/components/buttons/reconnect-button.tsx @@ -1,6 +1,7 @@ +import { RiRestartLine } from 'react-icons/ri'; + import { RemoteButton } from '/@/remote/components/buttons/remote-button'; import { useConnected, useReconnect } from '/@/remote/store'; -import { RiRestartLine } from 'react-icons/ri'; export const ReconnectButton = () => { const connected = useConnected(); @@ -10,10 +11,10 @@ export const ReconnectButton = () => { reconnect()} size="xl" tooltip={connected ? 'Reconnect' : 'Not connected. Reconnect.'} variant="default" - onClick={() => reconnect()} > diff --git a/src/remote/components/buttons/remote-button.tsx b/src/remote/components/buttons/remote-button.tsx index 7e8b5242..f211e81f 100644 --- a/src/remote/components/buttons/remote-button.tsx +++ b/src/remote/components/buttons/remote-button.tsx @@ -1,8 +1,11 @@ -import { MouseEvent, ReactNode, Ref, forwardRef } from 'react'; -import { Button, type ButtonProps as MantineButtonProps } from '@mantine/core'; -import { Tooltip } from '/@/renderer/components/tooltip'; +import { Button, type ButtonProps as MantineButtonProps, Tooltip } from '@mantine/core'; +import { forwardRef, MouseEvent, ReactNode, Ref } from 'react'; import styled from 'styled-components'; +export interface ButtonProps extends StyledButtonProps { + tooltip: string; +} + interface StyledButtonProps extends MantineButtonProps { $active?: boolean; children: ReactNode; @@ -11,10 +14,6 @@ interface StyledButtonProps extends MantineButtonProps { ref: Ref; } -export interface ButtonProps extends StyledButtonProps { - tooltip: string; -} - const StyledButton = styled(Button)` svg { display: flex; @@ -35,12 +34,12 @@ const StyledButton = styled(Button)` } `; -export const RemoteButton = forwardRef( - ({ children, tooltip, ...props }: ButtonProps, ref) => { +export const RemoteButton = forwardRef( + ({ children, tooltip, ...props }: any, ref) => { return ( ( ); }, ); - -RemoteButton.defaultProps = { - $active: false, - onClick: undefined, - onMouseDown: undefined, -}; diff --git a/src/remote/components/buttons/theme-button.tsx b/src/remote/components/buttons/theme-button.tsx index 4e6bfc24..097776e5 100644 --- a/src/remote/components/buttons/theme-button.tsx +++ b/src/remote/components/buttons/theme-button.tsx @@ -1,8 +1,9 @@ -import { useIsDark, useToggleDark } from '/@/remote/store'; -import { RiMoonLine, RiSunLine } from 'react-icons/ri'; -import { RemoteButton } from '/@/remote/components/buttons/remote-button'; -import { AppTheme } from '/@/renderer/themes/types'; import { useEffect } from 'react'; +import { RiMoonLine, RiSunLine } from 'react-icons/ri'; + +import { RemoteButton } from '/@/remote/components/buttons/remote-button'; +import { useIsDark, useToggleDark } from '/@/remote/store'; +import { AppTheme } from '/@/shared/types/domain-types'; export const ThemeButton = () => { const isDark = useIsDark(); @@ -16,10 +17,10 @@ export const ThemeButton = () => { return ( toggleDark()} size="xl" tooltip="Toggle Theme" variant="default" - onClick={() => toggleDark()} > {isDark ? : } diff --git a/src/remote/components/remote-container.tsx b/src/remote/components/remote-container.tsx index 595be38c..f2b295be 100644 --- a/src/remote/components/remote-container.tsx +++ b/src/remote/components/remote-container.tsx @@ -1,9 +1,7 @@ -import { useCallback } from 'react'; -import { Group, Image, Text, Title } from '@mantine/core'; -import { useInfo, useSend, useShowImage } from '/@/remote/store'; -import { RemoteButton } from '/@/remote/components/buttons/remote-button'; +import { Group, Image, Rating, Text, Title, Tooltip } from '@mantine/core'; import formatDuration from 'format-duration'; import debounce from 'lodash/debounce'; +import { useCallback } from 'react'; import { RiHeartLine, RiPauseFill, @@ -15,10 +13,11 @@ import { RiSkipForwardFill, RiVolumeUpFill, } from 'react-icons/ri'; -import { PlayerRepeat, PlayerStatus } from '/@/renderer/types'; + +import { RemoteButton } from '/@/remote/components/buttons/remote-button'; import { WrapperSlider } from '/@/remote/components/wrapped-slider'; -import { Tooltip } from '/@/renderer/components/tooltip'; -import { Rating } from '/@/renderer/components/rating'; +import { useInfo, useSend, useShowImage } from '/@/remote/store'; +import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types'; export const RemoteContainer = () => { const { position, repeat, shuffle, song, status, volume } = useInfo(); @@ -62,16 +61,14 @@ export const RemoteContainer = () => { > send({ event: 'previous' })} tooltip="Previous track" variant="default" - onClick={() => send({ event: 'previous' })} > { if (status === PlayerStatus.PLAYING) { send({ event: 'pause' }); @@ -79,6 +76,8 @@ export const RemoteContainer = () => { send({ event: 'play' }); } }} + tooltip={id && status === PlayerStatus.PLAYING ? 'Pause' : 'Play'} + variant="default" > {id && status === PlayerStatus.PLAYING ? ( @@ -88,9 +87,9 @@ export const RemoteContainer = () => { send({ event: 'next' })} tooltip="Next track" variant="default" - onClick={() => send({ event: 'next' })} > @@ -101,14 +100,15 @@ export const RemoteContainer = () => { > send({ event: 'shuffle' })} tooltip={shuffle ? 'Shuffle tracks' : 'Shuffle disabled'} variant="default" - onClick={() => send({ event: 'shuffle' })} > send({ event: 'repeat' })} tooltip={`Repeat ${ repeat === PlayerRepeat.ONE ? 'One' @@ -117,7 +117,6 @@ export const RemoteContainer = () => { : 'none' }`} variant="default" - onClick={() => send({ event: 'repeat' })} > {repeat === undefined || repeat === PlayerRepeat.ONE ? ( @@ -128,13 +127,13 @@ export const RemoteContainer = () => { { if (!id) return; send({ event: 'favorite', favorite: !song.userFavorite, id }); }} + tooltip={song?.userFavorite ? 'Unfavorite' : 'Favorite'} + variant="default" > @@ -145,10 +144,10 @@ export const RemoteContainer = () => { openDelay={1000} > debouncedSetRating(0)} + sx={{ margin: 'auto' }} + value={song.userRating ?? 0} /> @@ -159,14 +158,15 @@ export const RemoteContainer = () => { label={(value) => formatDuration(value * 1e3)} leftLabel={formatDuration(position * 1e3)} max={song.duration / 1e3} + onChangeEnd={(e) => send({ event: 'position', position: e })} rightLabel={formatDuration(song.duration)} value={position} - onChangeEnd={(e) => send({ event: 'position', position: e })} /> )} } max={100} + onChangeEnd={(e) => send({ event: 'volume', volume: e })} rightLabel={ { } value={volume ?? 0} - onChangeEnd={(e) => send({ event: 'volume', volume: e })} /> {showImage && ( send({ event: 'proxy' })} + src={song?.imageUrl?.replaceAll(/&(size|width|height=\d+)/g, '')} /> )} diff --git a/src/remote/components/shell.tsx b/src/remote/components/shell.tsx index 1244f6c9..dff0ef08 100644 --- a/src/remote/components/shell.tsx +++ b/src/remote/components/shell.tsx @@ -9,10 +9,11 @@ import { Skeleton, Title, } from '@mantine/core'; -import { ThemeButton } from '/@/remote/components/buttons/theme-button'; + import { ImageButton } from '/@/remote/components/buttons/image-button'; -import { RemoteContainer } from '/@/remote/components/remote-container'; import { ReconnectButton } from '/@/remote/components/buttons/reconnect-button'; +import { ThemeButton } from '/@/remote/components/buttons/theme-button'; +import { RemoteContainer } from '/@/remote/components/remote-container'; import { useConnected } from '/@/remote/store'; export const Shell = () => { diff --git a/src/remote/components/wrapped-slider.tsx b/src/remote/components/wrapped-slider.tsx index 92729df3..c0d83ed6 100644 --- a/src/remote/components/wrapped-slider.tsx +++ b/src/remote/components/wrapped-slider.tsx @@ -1,7 +1,6 @@ -import { useState, ReactNode } from 'react'; -import { SliderProps } from '@mantine/core'; +import { rem, Slider, SliderProps } from '@mantine/core'; +import { ReactNode, useState } from 'react'; import styled from 'styled-components'; -import { PlayerbarSlider } from '/@/renderer/features/player/components/playerbar-slider'; const SliderContainer = styled.div` display: flex; @@ -25,6 +24,54 @@ const SliderWrapper = styled.div` height: 100%; `; +const PlayerbarSlider = ({ ...props }: SliderProps) => { + return ( + { + e?.stopPropagation(); + }} + /> + ); +}; + export interface WrappedProps extends Omit { leftLabel?: ReactNode; onChangeEnd: (value: number) => void; @@ -43,9 +90,6 @@ export const WrapperSlider = ({ leftLabel, rightLabel, value, ...props }: Wrappe { setIsSeeking(true); setSeek(e); @@ -54,6 +98,9 @@ export const WrapperSlider = ({ leftLabel, rightLabel, value, ...props }: Wrappe props.onChangeEnd(e); setIsSeeking(false); }} + size={6} + value={!isSeeking ? (value ?? 0) : seek} + w="100%" /> {rightLabel && {rightLabel}} diff --git a/src/remote/index.tsx b/src/remote/index.tsx index f428da48..24e2521b 100644 --- a/src/remote/index.tsx +++ b/src/remote/index.tsx @@ -1,5 +1,6 @@ import { Notifications } from '@mantine/notifications'; import { createRoot } from 'react-dom/client'; + import { App } from '/@/remote/app'; const container = document.getElementById('root')! as HTMLElement; diff --git a/src/remote/service-worker.ts b/src/remote/service-worker.ts index 08dffa56..2b723331 100644 --- a/src/remote/service-worker.ts +++ b/src/remote/service-worker.ts @@ -1,10 +1,9 @@ /// export type {}; -// eslint-disable-next-line no-undef + declare const self: ServiceWorkerGlobalScope; -// eslint-disable-next-line no-restricted-globals const url = new URL(location.toString()); const version = url.searchParams.get('version'); const prod = url.searchParams.get('prod') === 'true'; diff --git a/src/remote/store/index.ts b/src/remote/store/index.ts index be0ad642..3f5d81f9 100644 --- a/src/remote/store/index.ts +++ b/src/remote/store/index.ts @@ -1,13 +1,20 @@ -import { hideNotification, showNotification } from '@mantine/notifications'; import type { NotificationProps as MantineNotificationProps } from '@mantine/notifications'; + +import { hideNotification, showNotification } from '@mantine/notifications'; import merge from 'lodash/merge'; import { create } from 'zustand'; import { devtools, persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; -import type { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/remote/types'; -interface StatefulWebSocket extends WebSocket { - natural: boolean; +import { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/shared/types/remote-types'; + +export interface SettingsSlice extends SettingsState { + actions: { + reconnect: () => void; + send: (data: ClientEvent) => void; + toggleIsDark: () => void; + toggleShowImage: () => void; + }; } interface SettingsState { @@ -18,13 +25,8 @@ interface SettingsState { socket?: StatefulWebSocket; } -export interface SettingsSlice extends SettingsState { - actions: { - reconnect: () => void; - send: (data: ClientEvent) => void; - toggleIsDark: () => void; - toggleShowImage: () => void; - }; +interface StatefulWebSocket extends WebSocket { + natural: boolean; } const initialState: SettingsState = { @@ -106,19 +108,18 @@ export const useRemoteStore = create()( const credentials = await fetch('/credentials'); authHeader = await credentials.text(); } catch (error) { - console.error('Failed to get credentials'); + console.error('Failed to get credentials', error); } set((state) => { const socket = new WebSocket( - // eslint-disable-next-line no-restricted-globals location.href.replace('http', 'ws'), ) as StatefulWebSocket; socket.natural = false; socket.addEventListener('message', (message) => { - const { event, data } = JSON.parse(message.data) as ServerEvent; + const { data, event } = JSON.parse(message.data) as ServerEvent; switch (event) { case 'error': { @@ -207,7 +208,6 @@ export const useRemoteStore = create()( socket.addEventListener('close', (reason) => { if (reason.code === 4002 || reason.code === 4003) { - // eslint-disable-next-line no-restricted-globals location.reload(); } else if (reason.code === 4000) { toast.warn({ diff --git a/src/renderer/api/controller.ts b/src/renderer/api/controller.ts index c42281f9..10a4507f 100644 --- a/src/renderer/api/controller.ts +++ b/src/renderer/api/controller.ts @@ -1,11 +1,14 @@ -import type { AuthenticationResponse, ControllerEndpoint, ServerType } from '/@/renderer/api/types'; - import i18n from '/@/i18n/i18n'; import { JellyfinController } from '/@/renderer/api/jellyfin/jellyfin-controller'; import { NavidromeController } from '/@/renderer/api/navidrome/navidrome-controller'; import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller'; import { toast } from '/@/renderer/components/toast/index'; import { useAuthStore } from '/@/renderer/store'; +import { + AuthenticationResponse, + ControllerEndpoint, + ServerType, +} from '/@/shared/types/domain-types'; type ApiController = { jellyfin: ControllerEndpoint; diff --git a/src/renderer/api/jellyfin/jellyfin-api.ts b/src/renderer/api/jellyfin/jellyfin-api.ts index 82fc61cc..0be34916 100644 --- a/src/renderer/api/jellyfin/jellyfin-api.ts +++ b/src/renderer/api/jellyfin/jellyfin-api.ts @@ -7,10 +7,11 @@ import { z } from 'zod'; import packageJson from '../../../../package.json'; import i18n from '/@/i18n/i18n'; -import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types'; -import { ServerListItem } from '/@/renderer/api/types'; -import { authenticationFailure, getClientType } from '/@/renderer/api/utils'; +import { authenticationFailure } from '/@/renderer/api/utils'; import { useAuthStore } from '/@/renderer/store'; +import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; +import { getClientType } from '/@/shared/api/utils'; +import { ServerListItem } from '/@/shared/types/domain-types'; const c = initContract(); diff --git a/src/renderer/api/jellyfin/jellyfin-controller.ts b/src/renderer/api/jellyfin/jellyfin-controller.ts index 564c6cba..54f1f0b1 100644 --- a/src/renderer/api/jellyfin/jellyfin-controller.ts +++ b/src/renderer/api/jellyfin/jellyfin-controller.ts @@ -1,12 +1,11 @@ import chunk from 'lodash/chunk'; import { z } from 'zod'; -import { jfNormalize } from './jellyfin-normalize'; - -import { ServerFeature } from '/@/renderer/api/features-types'; -import { JFSongListSort, JFSortOrder } from '/@/renderer/api/jellyfin.types'; import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api'; -import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types'; +import { JFSongListSort, JFSortOrder } from '/@/shared/api/jellyfin.types'; +import { jfNormalize } from '/@/shared/api/jellyfin/jellyfin-normalize'; +import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; +import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils'; import { albumArtistListSortMap, albumListSortMap, @@ -18,8 +17,8 @@ import { Song, songListSortMap, sortOrderMap, -} from '/@/renderer/api/types'; -import { getFeatures, hasFeature, VersionInfo } from '/@/renderer/api/utils'; +} from '/@/shared/types/domain-types'; +import { ServerFeature } from '/@/shared/types/features-types'; const formatCommaDelimitedString = (value: string[]) => { return value.join(','); @@ -282,7 +281,7 @@ export const JellyfinController: ControllerEndpoint = { throw new Error('No userId found'); } - const yearsGroup = []; + const yearsGroup: string[] = []; if (query.minYear && query.maxYear) { for (let i = Number(query.minYear); i <= Number(query.maxYear); i += 1) { yearsGroup.push(String(i)); @@ -555,7 +554,7 @@ export const JellyfinController: ControllerEndpoint = { throw new Error('No userId found'); } - const yearsGroup = []; + const yearsGroup: string[] = []; if (query.minYear && query.maxYear) { for (let i = Number(query.minYear); i <= Number(query.maxYear); i += 1) { yearsGroup.push(String(i)); @@ -692,7 +691,7 @@ export const JellyfinController: ControllerEndpoint = { throw new Error('No userId found'); } - const yearsGroup = []; + const yearsGroup: string[] = []; if (query.minYear && query.maxYear) { for (let i = Number(query.minYear); i <= Number(query.maxYear); i += 1) { yearsGroup.push(String(i)); diff --git a/src/renderer/api/navidrome/navidrome-api.ts b/src/renderer/api/navidrome/navidrome-api.ts index 551d5bea..dbddf4de 100644 --- a/src/renderer/api/navidrome/navidrome-api.ts +++ b/src/renderer/api/navidrome/navidrome-api.ts @@ -5,13 +5,13 @@ import debounce from 'lodash/debounce'; import omitBy from 'lodash/omitBy'; import qs from 'qs'; -import { ndType } from './navidrome-types'; - import i18n from '/@/i18n/i18n'; -import { ServerListItem } from '/@/renderer/api/types'; -import { authenticationFailure, resultWithHeaders } from '/@/renderer/api/utils'; -import { toast } from '/@/renderer/components/toast'; +import { authenticationFailure } from '/@/renderer/api/utils'; +import { toast } from '/@/renderer/components'; import { useAuthStore } from '/@/renderer/store'; +import { ndType } from '/@/shared/api/navidrome/navidrome-types'; +import { resultWithHeaders } from '/@/shared/api/utils'; +import { ServerListItem } from '/@/shared/types/domain-types'; const localSettings = isElectron() ? window.api.localSettings : null; @@ -274,7 +274,6 @@ axiosClient.interceptors.response.use( const currentServer = useAuthStore.getState().currentServer; if (localSettings && currentServer?.savePassword) { - // eslint-disable-next-line promise/no-promise-in-callback return localSettings .passwordGet(currentServer.id) .then(async (password: null | string) => { diff --git a/src/renderer/api/navidrome/navidrome-controller.ts b/src/renderer/api/navidrome/navidrome-controller.ts index 84b2b986..759fa565 100644 --- a/src/renderer/api/navidrome/navidrome-controller.ts +++ b/src/renderer/api/navidrome/navidrome-controller.ts @@ -1,3 +1,12 @@ +import { ndApiClient } from '/@/renderer/api/navidrome/navidrome-api'; +import { ssApiClient } from '/@/renderer/api/subsonic/subsonic-api'; +import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller'; +import { NDSongListSort } from '/@/shared/api/navidrome.types'; +import { ndNormalize } from '/@/shared/api/navidrome/navidrome-normalize'; +import { ndType } from '/@/shared/api/navidrome/navidrome-types'; +import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize'; +import { SubsonicExtensions } from '/@/shared/api/subsonic/subsonic-types'; +import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils'; import { albumArtistListSortMap, albumListSortMap, @@ -12,18 +21,8 @@ import { songListSortMap, sortOrderMap, userListSortMap, -} from '../types'; - -import { ServerFeature, ServerFeatures } from '/@/renderer/api/features-types'; -import { NDSongListSort } from '/@/renderer/api/navidrome.types'; -import { ndApiClient } from '/@/renderer/api/navidrome/navidrome-api'; -import { ndNormalize } from '/@/renderer/api/navidrome/navidrome-normalize'; -import { ndType } from '/@/renderer/api/navidrome/navidrome-types'; -import { ssApiClient } from '/@/renderer/api/subsonic/subsonic-api'; -import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller'; -import { ssNormalize } from '/@/renderer/api/subsonic/subsonic-normalize'; -import { SubsonicExtensions } from '/@/renderer/api/subsonic/subsonic-types'; -import { getFeatures, hasFeature, VersionInfo } from '/@/renderer/api/utils'; +} from '/@/shared/types/domain-types'; +import { ServerFeature, ServerFeatures } from '/@/shared/types/features-types'; const VERSION_INFO: VersionInfo = [ ['0.55.0', { [ServerFeature.BFR]: [1] }], diff --git a/src/renderer/api/query-keys.ts b/src/renderer/api/query-keys.ts index 1c071e3a..d14444c0 100644 --- a/src/renderer/api/query-keys.ts +++ b/src/renderer/api/query-keys.ts @@ -1,5 +1,3 @@ -import { QueryFunctionContext } from '@tanstack/react-query'; - import type { AlbumArtistDetailQuery, AlbumArtistListQuery, @@ -19,9 +17,11 @@ import type { SongListQuery, TopSongListQuery, UserListQuery, -} from './types'; +} from '/@/shared/types/domain-types'; -import { LyricSource } from './types'; +import { QueryFunctionContext } from '@tanstack/react-query'; + +import { LyricSource } from '/@/shared/types/domain-types'; export const splitPaginatedQuery = (key: any) => { const { limit, startIndex, ...filter } = key || {}; diff --git a/src/renderer/api/subsonic/subsonic-api.ts b/src/renderer/api/subsonic/subsonic-api.ts index f11d5734..a733430a 100644 --- a/src/renderer/api/subsonic/subsonic-api.ts +++ b/src/renderer/api/subsonic/subsonic-api.ts @@ -5,9 +5,9 @@ import qs from 'qs'; import { z } from 'zod'; import i18n from '/@/i18n/i18n'; -import { ssType } from '/@/renderer/api/subsonic/subsonic-types'; -import { ServerListItem } from '/@/renderer/api/types'; import { toast } from '/@/renderer/components/toast/index'; +import { ssType } from '/@/shared/api/subsonic/subsonic-types'; +import { ServerListItem } from '/@/shared/types/domain-types'; const c = initContract(); diff --git a/src/renderer/api/subsonic/subsonic-controller.ts b/src/renderer/api/subsonic/subsonic-controller.ts index 6bea97f8..2692ab59 100644 --- a/src/renderer/api/subsonic/subsonic-controller.ts +++ b/src/renderer/api/subsonic/subsonic-controller.ts @@ -3,10 +3,10 @@ import filter from 'lodash/filter'; import orderBy from 'lodash/orderBy'; import md5 from 'md5'; -import { ServerFeatures } from '/@/renderer/api/features-types'; import { ssApiClient } from '/@/renderer/api/subsonic/subsonic-api'; -import { ssNormalize } from '/@/renderer/api/subsonic/subsonic-normalize'; -import { AlbumListSortType, SubsonicExtensions } from '/@/renderer/api/subsonic/subsonic-types'; +import { randomString } from '/@/renderer/utils'; +import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize'; +import { AlbumListSortType, SubsonicExtensions } from '/@/shared/api/subsonic/subsonic-types'; import { AlbumListSort, ControllerEndpoint, @@ -18,8 +18,8 @@ import { sortAlbumList, SortOrder, sortSongList, -} from '/@/renderer/api/types'; -import { randomString } from '/@/renderer/utils'; +} from '/@/shared/types/domain-types'; +import { ServerFeatures } from '/@/shared/types/features-types'; const ALBUM_LIST_SORT_MAPPING: Record = { [AlbumListSort.ALBUM_ARTIST]: AlbumListSortType.ALPHABETICAL_BY_ARTIST, @@ -287,7 +287,7 @@ export const SubsonicController: ControllerEndpoint = { let type = ALBUM_LIST_SORT_MAPPING[query.sortBy] ?? AlbumListSortType.ALPHABETICAL_BY_NAME; if (query.artistIds) { - const promises = []; + const promises: any[] = []; for (const artistId of query.artistIds) { promises.push( @@ -858,8 +858,8 @@ export const SubsonicController: ControllerEndpoint = { return ssNormalize.song(res.body.song, apiClientProps.server); }, getSongList: async ({ apiClientProps, query }) => { - const fromAlbumPromises = []; - const artistDetailPromises = []; + const fromAlbumPromises: any[] = []; + const artistDetailPromises: any[] = []; let results: any[] = []; if (query.searchTerm) { diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index b5deb049..d6bff675 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -6,23 +6,13 @@ import isElectron from 'is-electron'; import { useEffect, useMemo, useRef, useState } from 'react'; import { initSimpleImg } from 'react-simple-img'; -import i18n from '../i18n/i18n'; -import { toast } from './components'; -import { useTheme } from './hooks'; -import { AppRouter } from './router/app-router'; import './styles/global.scss'; import '@ag-grid-community/styles/ag-grid.css'; import 'overlayscrollbars/overlayscrollbars.css'; -import { - useCssSettings, - useHotkeySettings, - usePlaybackSettings, - useRemoteSettings, - useSettingsStore, -} from './store/settings.store'; - +import i18n from '/@/i18n/i18n'; +import { toast } from '/@/renderer/components'; import { ContextMenuProvider } from '/@/renderer/features/context-menu'; import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc'; import { PlayQueueHandlerContext } from '/@/renderer/features/player'; @@ -30,12 +20,23 @@ import { WebAudioContext } from '/@/renderer/features/player/context/webaudio-co import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add'; import { updateSong } from '/@/renderer/features/player/update-remote-song'; import { getMpvProperties } from '/@/renderer/features/settings/components/playback/mpv-settings'; +import { useTheme } from '/@/renderer/hooks'; import { useServerVersion } from '/@/renderer/hooks/use-server-version'; import { IsUpdatedDialog } from '/@/renderer/is-updated-dialog'; -import { PlayerState, usePlayerStore, useQueueControls } from '/@/renderer/store'; -import { FontType, PlaybackType, PlayerStatus, WebAudio } from '/@/renderer/types'; +import { AppRouter } from '/@/renderer/router/app-router'; +import { + PlayerState, + useCssSettings, + useHotkeySettings, + usePlaybackSettings, + usePlayerStore, + useQueueControls, + useRemoteSettings, + useSettingsStore, +} from '/@/renderer/store'; import { sanitizeCss } from '/@/renderer/utils/sanitize'; import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data'; +import { FontType, PlaybackType, PlayerStatus, WebAudio } from '/@/shared/types/types'; ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]); @@ -58,8 +59,8 @@ export const App = () => { const handlePlayQueueAdd = useHandlePlayQueueAdd(); const { clearQueue, restoreQueue } = useQueueControls(); const remoteSettings = useRemoteSettings(); - const textStyleRef = useRef(); - const cssRef = useRef(); + const textStyleRef = useRef(null); + const cssRef = useRef(null); useDiscordRpc(); useServerVersion(); diff --git a/src/renderer/components/audio-player/index.tsx b/src/renderer/components/audio-player/index.tsx index fedb6c9a..2ed080ee 100644 --- a/src/renderer/components/audio-player/index.tsx +++ b/src/renderer/components/audio-player/index.tsx @@ -1,17 +1,9 @@ -import type { Song } from '/@/renderer/api/types'; -import type { CrossfadeStyle } from '/@/renderer/types'; +import type { Song } from '/@/shared/types/domain-types'; +import type { CrossfadeStyle } from '/@/shared/types/types'; import type { ReactPlayerProps } from 'react-player'; import isElectron from 'is-electron'; -import { - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useMemo, - useRef, - useState, -} from 'react'; +import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import ReactPlayer from 'react-player/lazy'; import { api } from '/@/renderer/api'; @@ -23,7 +15,7 @@ import { toast } from '/@/renderer/components/toast'; import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio'; import { getServerById, TranscodingConfig, usePlaybackSettings, useSpeed } from '/@/renderer/store'; import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store'; -import { PlaybackStyle, PlayerStatus } from '/@/renderer/types'; +import { PlaybackStyle, PlayerStatus } from '/@/shared/types/types'; export type AudioPlayerProgress = { loaded: number; @@ -33,9 +25,11 @@ export type AudioPlayerProgress = { }; interface AudioPlayerProps extends ReactPlayerProps { + autoNext: () => void; crossfadeDuration: number; crossfadeStyle: CrossfadeStyle; currentPlayer: 1 | 2; + muted: boolean; playbackStyle: PlaybackStyle; player1?: Song; player2?: Song; @@ -93,369 +87,360 @@ const useSongUrl = (transcode: TranscodingConfig, current: boolean, song?: Song) }, [current, song?.uniqueId, song?.serverId, song?.streamUrl, transcode]); }; -export const AudioPlayer = forwardRef( - ( - { - autoNext, - crossfadeDuration, - crossfadeStyle, - currentPlayer, - muted, - playbackStyle, - player1, - player2, - status, - volume, - }: AudioPlayerProps, - ref: any, - ) => { - const player1Ref = useRef(null); - const player2Ref = useRef(null); - const [isTransitioning, setIsTransitioning] = useState(false); - const audioDeviceId = useSettingsStore((state) => state.playback.audioDeviceId); - const playback = useSettingsStore((state) => state.playback.mpvProperties); - const shouldUseWebAudio = useSettingsStore((state) => state.playback.webAudio); - const { resetSampleRate } = useSettingsStoreActions(); - const playbackSpeed = useSpeed(); - const { transcode } = usePlaybackSettings(); +export const AudioPlayer = ({ ref, ...props }: AudioPlayerProps) => { + const { + autoNext, + crossfadeDuration, + crossfadeStyle, + currentPlayer, + muted, + playbackStyle, + player1, + player2, + status, + volume, + } = props; - const stream1 = useSongUrl(transcode, currentPlayer === 1, player1); - const stream2 = useSongUrl(transcode, currentPlayer === 2, player2); + const player1Ref = useRef(null); + const player2Ref = useRef(null); + const [isTransitioning, setIsTransitioning] = useState(false); + const audioDeviceId = useSettingsStore((state) => state.playback.audioDeviceId); + const playback = useSettingsStore((state) => state.playback.mpvProperties); + const shouldUseWebAudio = useSettingsStore((state) => state.playback.webAudio); + const { resetSampleRate } = useSettingsStoreActions(); + const playbackSpeed = useSpeed(); + const { transcode } = usePlaybackSettings(); - const { setWebAudio, webAudio } = useWebAudio(); - const [player1Source, setPlayer1Source] = useState( - null, - ); - const [player2Source, setPlayer2Source] = useState( - null, - ); + const stream1 = useSongUrl(transcode, currentPlayer === 1, player1); + const stream2 = useSongUrl(transcode, currentPlayer === 2, player2); - const calculateReplayGain = useCallback( - (song: Song): number => { - if (playback.replayGainMode === 'no') { + const { setWebAudio, webAudio } = useWebAudio(); + const [player1Source, setPlayer1Source] = useState(null); + const [player2Source, setPlayer2Source] = useState(null); + + const calculateReplayGain = useCallback( + (song: Song): number => { + if (playback.replayGainMode === 'no') { + return 1; + } + + let gain: number | undefined; + let peak: number | undefined; + + if (playback.replayGainMode === 'track') { + gain = song.gain?.track ?? song.gain?.album; + peak = song.peak?.track ?? song.peak?.album; + } else { + gain = song.gain?.album ?? song.gain?.track; + peak = song.peak?.album ?? song.peak?.track; + } + + if (gain === undefined) { + gain = playback.replayGainFallbackDB; + + if (!gain) { return 1; } - - let gain: number | undefined; - let peak: number | undefined; - - if (playback.replayGainMode === 'track') { - gain = song.gain?.track ?? song.gain?.album; - peak = song.peak?.track ?? song.peak?.album; - } else { - gain = song.gain?.album ?? song.gain?.track; - peak = song.peak?.album ?? song.peak?.track; - } - - if (gain === undefined) { - gain = playback.replayGainFallbackDB; - - if (!gain) { - return 1; - } - } - - if (peak === undefined) { - peak = 1; - } - - const preAmp = playback.replayGainPreampDB ?? 0; - - // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification§ion=19 - // Normalized to max gain - const expectedGain = 10 ** ((gain + preAmp) / 20); - - if (playback.replayGainClip) { - return Math.min(expectedGain, 1 / peak); - } - return expectedGain; - }, - [ - playback.replayGainClip, - playback.replayGainFallbackDB, - playback.replayGainMode, - playback.replayGainPreampDB, - ], - ); - - useEffect(() => { - if (shouldUseWebAudio && 'AudioContext' in window) { - let context: AudioContext; - - try { - context = new AudioContext({ - latencyHint: 'playback', - sampleRate: playback.audioSampleRateHz || undefined, - }); - } catch (error) { - // In practice, this should never be hit because the UI should validate - // the range. However, the actual supported range is not guaranteed - toast.error({ message: (error as Error).message }); - context = new AudioContext({ latencyHint: 'playback' }); - resetSampleRate(); - } - - const gain = context.createGain(); - gain.connect(context.destination); - - setWebAudio!({ context, gain }); - - return () => { - return context.close(); - }; } - return () => {}; - // Intentionally ignore the sample rate dependency, as it makes things really messy - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useImperativeHandle(ref, () => ({ - get player1() { - return player1Ref?.current; - }, - get player2() { - return player2Ref?.current; - }, - })); + if (peak === undefined) { + peak = 1; + } - const handleOnEnded = () => { - autoNext(); - setIsTransitioning(false); - }; + const preAmp = playback.replayGainPreampDB ?? 0; - useEffect(() => { - if (status === PlayerStatus.PLAYING) { - if (currentPlayer === 1) { - // calling play() is not necessarily a safe option (https://developer.chrome.com/blog/play-request-was-interrupted) - // In practice, this failure is only likely to happen when using the 0-second wav: - // play() + play() in rapid succession will cause problems as the frist one ends the track. - player1Ref.current - ?.getInternalPlayer() - ?.play() - .catch(() => {}); - } else { - player2Ref.current - ?.getInternalPlayer() - ?.play() - .catch(() => {}); - } + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification§ion=19 + // Normalized to max gain + const expectedGain = 10 ** ((gain + preAmp) / 20); + + if (playback.replayGainClip) { + return Math.min(expectedGain, 1 / peak); + } + return expectedGain; + }, + [ + playback.replayGainClip, + playback.replayGainFallbackDB, + playback.replayGainMode, + playback.replayGainPreampDB, + ], + ); + + useEffect(() => { + if (shouldUseWebAudio && 'AudioContext' in window) { + let context: AudioContext; + + try { + context = new AudioContext({ + latencyHint: 'playback', + sampleRate: playback.audioSampleRateHz || undefined, + }); + } catch (error) { + // In practice, this should never be hit because the UI should validate + // the range. However, the actual supported range is not guaranteed + toast.error({ message: (error as Error).message }); + context = new AudioContext({ latencyHint: 'playback' }); + resetSampleRate(); + } + + const gain = context.createGain(); + gain.connect(context.destination); + + setWebAudio!({ context, gain }); + + return () => { + return context.close(); + }; + } + return () => {}; + // Intentionally ignore the sample rate dependency, as it makes things really messy + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useImperativeHandle(ref, () => ({ + get player1() { + return player1Ref?.current; + }, + get player2() { + return player2Ref?.current; + }, + })); + + const handleOnEnded = () => { + autoNext(); + setIsTransitioning(false); + }; + + useEffect(() => { + if (status === PlayerStatus.PLAYING) { + if (currentPlayer === 1) { + // calling play() is not necessarily a safe option (https://developer.chrome.com/blog/play-request-was-interrupted) + // In practice, this failure is only likely to happen when using the 0-second wav: + // play() + play() in rapid succession will cause problems as the frist one ends the track. + player1Ref.current + ?.getInternalPlayer() + ?.play() + .catch(() => {}); } else { - player1Ref.current?.getInternalPlayer()?.pause(); - player2Ref.current?.getInternalPlayer()?.pause(); + player2Ref.current + ?.getInternalPlayer() + ?.play() + .catch(() => {}); } - }, [currentPlayer, status]); + } else { + player1Ref.current?.getInternalPlayer()?.pause(); + player2Ref.current?.getInternalPlayer()?.pause(); + } + }, [currentPlayer, status]); - const handleCrossfade1 = useCallback( - (e: AudioPlayerProgress) => { - return crossfadeHandler({ - currentPlayer, - currentPlayerRef: player1Ref, - currentTime: e.playedSeconds, - duration: getDuration(player1Ref), - fadeDuration: crossfadeDuration, - fadeType: crossfadeStyle, - isTransitioning, - nextPlayerRef: player2Ref, - player: 1, - setIsTransitioning, - volume, - }); - }, - [crossfadeDuration, crossfadeStyle, currentPlayer, isTransitioning, volume], - ); + const handleCrossfade1 = useCallback( + (e: AudioPlayerProgress) => { + return crossfadeHandler({ + currentPlayer, + currentPlayerRef: player1Ref, + currentTime: e.playedSeconds, + duration: getDuration(player1Ref), + fadeDuration: crossfadeDuration, + fadeType: crossfadeStyle, + isTransitioning, + nextPlayerRef: player2Ref, + player: 1, + setIsTransitioning, + volume, + }); + }, + [crossfadeDuration, crossfadeStyle, currentPlayer, isTransitioning, volume], + ); - const handleCrossfade2 = useCallback( - (e: AudioPlayerProgress) => { - return crossfadeHandler({ - currentPlayer, - currentPlayerRef: player2Ref, - currentTime: e.playedSeconds, - duration: getDuration(player2Ref), - fadeDuration: crossfadeDuration, - fadeType: crossfadeStyle, - isTransitioning, - nextPlayerRef: player1Ref, - player: 2, - setIsTransitioning, - volume, - }); - }, - [crossfadeDuration, crossfadeStyle, currentPlayer, isTransitioning, volume], - ); + const handleCrossfade2 = useCallback( + (e: AudioPlayerProgress) => { + return crossfadeHandler({ + currentPlayer, + currentPlayerRef: player2Ref, + currentTime: e.playedSeconds, + duration: getDuration(player2Ref), + fadeDuration: crossfadeDuration, + fadeType: crossfadeStyle, + isTransitioning, + nextPlayerRef: player1Ref, + player: 2, + setIsTransitioning, + volume, + }); + }, + [crossfadeDuration, crossfadeStyle, currentPlayer, isTransitioning, volume], + ); - const handleGapless1 = useCallback( - (e: AudioPlayerProgress) => { - return gaplessHandler({ - currentTime: e.playedSeconds, - duration: getDuration(player1Ref), - isFlac: player1?.container === 'flac', - isTransitioning, - nextPlayerRef: player2Ref, - setIsTransitioning, - }); - }, - [isTransitioning, player1?.container], - ); + const handleGapless1 = useCallback( + (e: AudioPlayerProgress) => { + return gaplessHandler({ + currentTime: e.playedSeconds, + duration: getDuration(player1Ref), + isFlac: player1?.container === 'flac', + isTransitioning, + nextPlayerRef: player2Ref, + setIsTransitioning, + }); + }, + [isTransitioning, player1?.container], + ); - const handleGapless2 = useCallback( - (e: AudioPlayerProgress) => { - return gaplessHandler({ - currentTime: e.playedSeconds, - duration: getDuration(player2Ref), - isFlac: player2?.container === 'flac', - isTransitioning, - nextPlayerRef: player1Ref, - setIsTransitioning, - }); - }, - [isTransitioning, player2?.container], - ); + const handleGapless2 = useCallback( + (e: AudioPlayerProgress) => { + return gaplessHandler({ + currentTime: e.playedSeconds, + duration: getDuration(player2Ref), + isFlac: player2?.container === 'flac', + isTransitioning, + nextPlayerRef: player1Ref, + setIsTransitioning, + }); + }, + [isTransitioning, player2?.container], + ); - useEffect(() => { - // Not standard, just used in chromium-based browsers. See - // https://developer.chrome.com/blog/audiocontext-setsinkid/. - // If the isElectron() check is every removed, fix this. - if (isElectron() && webAudio && 'setSinkId' in webAudio.context && audioDeviceId) { - const setSink = async () => { - try { - if (audioDeviceId !== 'default') { - // @ts-ignore - await webAudio.context.setSinkId(audioDeviceId); - } else { - // @ts-ignore - await webAudio.context.setSinkId(''); - } - } catch (error) { - toast.error({ message: `Error setting sink: ${(error as Error).message}` }); + useEffect(() => { + // Not standard, just used in chromium-based browsers. See + // https://developer.chrome.com/blog/audiocontext-setsinkid/. + // If the isElectron() check is every removed, fix this. + if (isElectron() && webAudio && 'setSinkId' in webAudio.context && audioDeviceId) { + const setSink = async () => { + try { + if (audioDeviceId !== 'default') { + await (webAudio.context as any).setSinkId(audioDeviceId); + } else { + await (webAudio.context as any).setSinkId(''); } - }; + } catch (error) { + toast.error({ message: `Error setting sink: ${(error as Error).message}` }); + } + }; - setSink(); - } - }, [audioDeviceId, webAudio]); + setSink(); + } + }, [audioDeviceId, webAudio]); - useEffect(() => { + useEffect(() => { + if (!webAudio) return; + + const sources = [player1Source ? player1 : null, player2Source ? player2 : null]; + const current = sources[currentPlayer - 1]; + + // Set the current replaygain + if (current) { + const newVolume = calculateReplayGain(current) * volume; + webAudio.gain.gain.setValueAtTime(Math.max(0, newVolume), 0); + } + + // Set the next track replaygain right before the end of this track + // Attempt to prevent pop-in for web audio. + const next = sources[3 - currentPlayer]; + if (next && current) { + const newVolume = calculateReplayGain(next) * volume; + webAudio.gain.gain.setValueAtTime( + Math.max(0, newVolume), + Math.max(0, (current.duration - 1) / 1000), + ); + } + }, [ + calculateReplayGain, + currentPlayer, + player1, + player1Source, + player2, + player2Source, + volume, + webAudio, + ]); + + const handlePlayer1Start = useCallback( + async (player: ReactPlayer) => { if (!webAudio) return; - - const sources = [player1Source ? player1 : null, player2Source ? player2 : null]; - const current = sources[currentPlayer - 1]; - - // Set the current replaygain - if (current) { - const newVolume = calculateReplayGain(current) * volume; - webAudio.gain.gain.setValueAtTime(Math.max(0, newVolume), 0); + if (player1Source) { + // This should fire once, only if the source is real (meaning we + // saw the dummy source) and the context is not ready + if (webAudio.context.state !== 'running') { + await webAudio.context.resume(); + } + return; } - // Set the next track replaygain right before the end of this track - // Attempt to prevent pop-in for web audio. - const next = sources[3 - currentPlayer]; - if (next && current) { - const newVolume = calculateReplayGain(next) * volume; - webAudio.gain.gain.setValueAtTime( - Math.max(0, newVolume), - Math.max(0, (current.duration - 1) / 1000), - ); + const internal = player.getInternalPlayer() as HTMLMediaElement | undefined; + if (internal) { + const { context, gain } = webAudio; + const source = context.createMediaElementSource(internal); + source.connect(gain); + setPlayer1Source(source); } - }, [ - calculateReplayGain, - currentPlayer, - player1, - player1Source, - player2, - player2Source, - volume, - webAudio, - ]); + }, + [player1Source, webAudio], + ); - const handlePlayer1Start = useCallback( - async (player: ReactPlayer) => { - if (!webAudio) return; - if (player1Source) { - // This should fire once, only if the source is real (meaning we - // saw the dummy source) and the context is not ready - if (webAudio.context.state !== 'running') { - await webAudio.context.resume(); - } - return; + const handlePlayer2Start = useCallback( + async (player: ReactPlayer) => { + if (!webAudio) return; + if (player2Source) { + if (webAudio.context.state !== 'running') { + await webAudio.context.resume(); } + return; + } - const internal = player.getInternalPlayer() as HTMLMediaElement | undefined; - if (internal) { - const { context, gain } = webAudio; - const source = context.createMediaElementSource(internal); - source.connect(gain); - setPlayer1Source(source); + const internal = player.getInternalPlayer() as HTMLMediaElement | undefined; + if (internal) { + const { context, gain } = webAudio; + const source = context.createMediaElementSource(internal); + source.connect(gain); + setPlayer2Source(source); + } + }, + [player2Source, webAudio], + ); + + // Bugfix for Safari: rather than use the `