From ae5d2525f18912a91d0bf3fa9dfe0ab68740fe92 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 26 Aug 2023 21:09:35 +0200 Subject: [PATCH 01/47] Add "apollo-client" dependencies --- package.json | 4 ++ yarn.lock | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c28a422..15e7d7b3 100644 --- a/package.json +++ b/package.json @@ -26,14 +26,17 @@ ] }, "dependencies": { + "@apollo/client": "^3.8.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fontsource/roboto": "^5.0.8", "@mui/icons-material": "^5.14.9", "@mui/material": "^5.14.9", "@vitejs/plugin-react-swc": "^3.3.2", + "apollo-upload-client": "^17.0.0", "axios": "^1.5.0", "file-selector": "^0.6.0", + "graphql-tag": "^2.12.6", "i18next": "^23.5.1", "i18next-browser-languagedetector": "^7.1.0", "react": "^18.2.0", @@ -48,6 +51,7 @@ "vite-tsconfig-paths": "^4.2.1" }, "devDependencies": { + "@types/apollo-upload-client": "^17.0.2", "@types/node": "^20.6.2", "@types/react": "^18.2.21", "@types/react-beautiful-dnd": "^13.1.4", diff --git a/yarn.lock b/yarn.lock index 93498958..b83e9ef8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,25 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@apollo/client@^3.7.0", "@apollo/client@^3.8.1": + version "3.8.3" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.8.3.tgz#7cd23307bbc788a0a9eda51e6a76f32db8282933" + integrity sha512-mK86JM6hCpMEBGDgdO9U8ZYS8r9lPjXE1tVGpJMdSFUsIcXpmEfHUAbbFpPtYmxn8Qa7XsYy0dwDaDhpf4UUPw== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@wry/context" "^0.7.3" + "@wry/equality" "^0.5.6" + "@wry/trie" "^0.4.3" + graphql-tag "^2.12.6" + hoist-non-react-statics "^3.3.2" + optimism "^0.17.5" + prop-types "^15.7.2" + response-iterator "^0.2.6" + symbol-observable "^4.0.0" + ts-invariant "^0.10.3" + tslib "^2.3.0" + zen-observable-ts "^1.2.5" + "@babel/code-frame@^7.0.0": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -345,6 +364,11 @@ resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-5.0.8.tgz#613b477a56f21b5705db1a67e995c033ef317f76" integrity sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA== +"@graphql-typed-document-node/core@^3.1.1": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@humanwhocodes/config-array@^0.11.11": version "0.11.11" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" @@ -609,6 +633,20 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@types/apollo-upload-client@^17.0.2": + version "17.0.2" + resolved "https://registry.yarnpkg.com/@types/apollo-upload-client/-/apollo-upload-client-17.0.2.tgz#15dc737663928be27c768117603dfc23c21514bb" + integrity sha512-NphAiBqzZv3iY8Cq+qWyi0QUFFzJ+nVd7QKI/iKV8RfILrpYDL69F/vlhjn4BNxKlmc3LxJHymcf3gFzLBwuZQ== + dependencies: + "@apollo/client" "^3.7.0" + "@types/extract-files" "*" + graphql "14 - 16" + +"@types/extract-files@*": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-8.1.1.tgz#11b67e795ad2c8b483431e8d4f190db2fd22944b" + integrity sha512-dMJJqBqyhsfJKuK7p7HyyNmki7qj1AlwhUKWx6KrU7i1K2T2SPsUsSUTWFmr/sEM1q8rfR8j5IyUmYrDbrhfjQ== + "@types/hoist-non-react-statics@^3.3.0": version "3.3.2" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" @@ -796,6 +834,27 @@ dependencies: "@swc/core" "^1.3.61" +"@wry/context@^0.7.0", "@wry/context@^0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.3.tgz#240f6dfd4db5ef54f81f6597f6714e58d4f476a1" + integrity sha512-Nl8WTesHp89RF803Se9X3IiHjdmLBrIvPMaJkl+rKVJAYyPsz1TEUbu89943HpvujtSJgDUx9W4vZw3K1Mr3sA== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.6": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.6.tgz#cd4a533c72c3752993ab8cbf682d3d20e3cb601e" + integrity sha512-D46sfMTngaYlrH+OspKf8mIJETntFnf6Hsjb0V41jAXJ7Bx2kB8Rv8RCUujuVWYttFtHkUNp7g+FwxNQAr6mXA== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.4.3.tgz#077d52c22365871bf3ffcbab8e95cb8bc5689af4" + integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== + dependencies: + tslib "^2.3.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -840,6 +899,13 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +apollo-upload-client@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-17.0.0.tgz#d9baaff8d14e54510de9f2855b487e75ca63b392" + integrity sha512-pue33bWVbdlXAGFPkgz53TTmxVMrKeQr0mdRcftNY+PoHIdbGZD0hoaXHvO6OePJAkFz7OiCFUf98p1G/9+Ykw== + dependencies: + extract-files "^11.0.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1679,6 +1745,11 @@ execa@^7.1.1: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +extract-files@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" + integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1913,6 +1984,18 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +"graphql@14 - 16": + version "16.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.0.tgz#374478b7f27b2dc6153c8f42c1b80157f79d79d4" + integrity sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg== + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -2570,6 +2653,15 @@ open@^9.1.0: is-inside-container "^1.0.0" is-wsl "^2.2.0" +optimism@^0.17.5: + version "0.17.5" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.17.5.tgz#a4c78b3ad12c58623abedbebb4f2f2c19b8e8816" + integrity sha512-TEcp8ZwK1RczmvMnvktxHSF2tKgMWjJ71xEFGX5ApLh67VsMSTy1ZUlipJw8W+KaqgOmQ+4pqwkeivY89j+4Vw== + dependencies: + "@wry/context" "^0.7.0" + "@wry/trie" "^0.4.3" + tslib "^2.3.0" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -2862,6 +2954,11 @@ resolve@^2.0.0-next.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +response-iterator@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" + integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -3098,6 +3195,11 @@ swr@^2.2.2: client-only "^0.0.1" use-sync-external-store "^1.2.0" +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + synckit@^0.8.5: version "0.8.5" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" @@ -3146,6 +3248,13 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== +ts-invariant@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c" + integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== + dependencies: + tslib "^2.1.0" + ts-node@^10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -3180,7 +3289,7 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0: +tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -3423,3 +3532,15 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zen-observable-ts@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58" + integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 55c1c51edd03f3e7559b32face8dd3e78301cd92 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:03:40 +0200 Subject: [PATCH 02/47] Create queries, mutations and subscriptions --- src/lib/graphql/Fragments.ts | 439 ++++++++++++++++++ src/lib/graphql/mutations/BackupMutation.ts | 31 ++ src/lib/graphql/mutations/CategoryMutation.ts | 105 +++++ src/lib/graphql/mutations/ChapterMutation.ts | 96 ++++ .../graphql/mutations/DownloaderMutation.ts | 130 ++++++ .../graphql/mutations/ExtensionMutation.ts | 59 +++ .../mutations/GlobalMetadataMutation.ts | 34 ++ src/lib/graphql/mutations/MangaMutation.ts | 106 +++++ .../graphql/mutations/ServerInfoMutation.ts | 23 + src/lib/graphql/mutations/SettingsMutation.ts | 34 ++ src/lib/graphql/mutations/SourceMutation.ts | 35 ++ src/lib/graphql/mutations/UpdaterMutation.ts | 42 ++ src/lib/graphql/queries/BackupQuery.ts | 30 ++ src/lib/graphql/queries/CategoryQuery.ts | 73 +++ src/lib/graphql/queries/ChapterQuery.ts | 57 +++ src/lib/graphql/queries/DownloaderQuery.ts | 20 + src/lib/graphql/queries/ExtensionQuery.ts | 57 +++ .../graphql/queries/GlobalMetadataQuery.ts | 55 +++ src/lib/graphql/queries/MangaQuery.ts | 59 +++ src/lib/graphql/queries/ServerInfoQuery.ts | 52 +++ src/lib/graphql/queries/SettingsQuery.ts | 20 + src/lib/graphql/queries/SourceQuery.ts | 30 ++ src/lib/graphql/queries/UpdaterQuery.ts | 28 ++ .../subscriptions/DownloaderSubscription.ts | 20 + .../subscriptions/ServerInfoSubscription.ts | 20 + .../subscriptions/UpdaterSubscription.ts | 20 + 26 files changed, 1675 insertions(+) create mode 100644 src/lib/graphql/Fragments.ts create mode 100644 src/lib/graphql/mutations/BackupMutation.ts create mode 100644 src/lib/graphql/mutations/CategoryMutation.ts create mode 100644 src/lib/graphql/mutations/ChapterMutation.ts create mode 100644 src/lib/graphql/mutations/DownloaderMutation.ts create mode 100644 src/lib/graphql/mutations/ExtensionMutation.ts create mode 100644 src/lib/graphql/mutations/GlobalMetadataMutation.ts create mode 100644 src/lib/graphql/mutations/MangaMutation.ts create mode 100644 src/lib/graphql/mutations/ServerInfoMutation.ts create mode 100644 src/lib/graphql/mutations/SettingsMutation.ts create mode 100644 src/lib/graphql/mutations/SourceMutation.ts create mode 100644 src/lib/graphql/mutations/UpdaterMutation.ts create mode 100644 src/lib/graphql/queries/BackupQuery.ts create mode 100644 src/lib/graphql/queries/CategoryQuery.ts create mode 100644 src/lib/graphql/queries/ChapterQuery.ts create mode 100644 src/lib/graphql/queries/DownloaderQuery.ts create mode 100644 src/lib/graphql/queries/ExtensionQuery.ts create mode 100644 src/lib/graphql/queries/GlobalMetadataQuery.ts create mode 100644 src/lib/graphql/queries/MangaQuery.ts create mode 100644 src/lib/graphql/queries/ServerInfoQuery.ts create mode 100644 src/lib/graphql/queries/SettingsQuery.ts create mode 100644 src/lib/graphql/queries/SourceQuery.ts create mode 100644 src/lib/graphql/queries/UpdaterQuery.ts create mode 100644 src/lib/graphql/subscriptions/DownloaderSubscription.ts create mode 100644 src/lib/graphql/subscriptions/ServerInfoSubscription.ts create mode 100644 src/lib/graphql/subscriptions/UpdaterSubscription.ts diff --git a/src/lib/graphql/Fragments.ts b/src/lib/graphql/Fragments.ts new file mode 100644 index 00000000..e801d2da --- /dev/null +++ b/src/lib/graphql/Fragments.ts @@ -0,0 +1,439 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; + +export const PAGE_INFO = gql` + fragment PAGE_INFO on PageInfo { + endCursor + hasNextPage + hasPreviousPage + startCursor + } +`; + +export const GLOBAL_METADATA = gql` + fragment GLOBAL_METADATA on GlobalMetaType { + key + value + } +`; + +export const FULL_CATEGORY_FIELDS = gql` + fragment FULL_CATEGORY_FIELDS on CategoryType { + default + id + includeInUpdate + name + order + meta { + key + value + } + mangas { + totalCount + } + } +`; + +export const PARTIAL_SOURCE_FIELDS = gql` + fragment PARTIAL_SOURCE_FIELDS on SourceType { + displayName + iconUrl + id + isConfigurable + isNsfw + lang + name + supportsLatest + } +`; + +export const FULL_SOURCE_FIELDS = gql` + ${PARTIAL_SOURCE_FIELDS} + fragment FULL_SOURCE_FIELDS on SourceType { + ...PARTIAL_SOURCE_FIELDS + preferences { + ... on CheckBoxPreference { + type: __typename + CheckBoxCheckBoxCurrentValue: currentValue + summary + CheckBoxDefault: default + key + CheckBoxTitle: title + } + ... on EditTextPreference { + type: __typename + EditTextPreferenceCurrentValue: currentValue + EditTextPreferenceDefault: default + EditTextPreferenceTitle: title + text + summary + key + dialogTitle + dialogMessage + } + ... on SwitchPreference { + type: __typename + SwitchPreferenceCurrentValue: currentValue + summary + key + SwitchPreferenceDefault: default + SwitchPreferenceTitle: title + } + ... on MultiSelectListPreference { + type: __typename + dialogMessage + dialogTitle + MultiSelectListPreferenceTitle: title + summary + key + entryValues + entries + MultiSelectListPreferenceDefault: default + MultiSelectListPreferenceCurrentValue: currentValue + } + ... on ListPreference { + type: __typename + ListPreferenceCurrentValue: currentValue + ListPreferenceDefault: default + ListPreferenceTitle: title + summary + key + entryValues + entries + } + } + filters { + ... on TriStateFilter { + type: __typename + name + TriStateFilterDefault: default + } + ... on CheckBoxFilter { + type: __typename + CheckBoxFilterDefault: default + name + } + ... on TextFilter { + type: __typename + name + TextFilterDefault: default + } + ... on SortFilter { + type: __typename + values + name + SortFilterDefault: default { + ascending + index + } + } + ... on SeparatorFilter { + type: __typename + name + } + ... on SelectFilter { + type: __typename + values + name + SelectFilterDefault: default + } + ... on HeaderFilter { + type: __typename + name + } + ... on GroupFilter { + type: __typename + name + filters { + ... on CheckBoxFilter { + type: __typename + CheckBoxFilterDefault: default + name + } + ... on HeaderFilter { + type: __typename + name + } + ... on SelectFilter { + type: __typename + SelectFilterDefault: default + name + values + } + ... on TriStateFilter { + type: __typename + TriStateFilterDefault: default + name + } + ... on TextFilter { + type: __typename + TextFilterDefault: default + name + } + ... on SortFilter { + type: __typename + SorSortFilterDefault: default { + ascending + index + } + name + values + } + ... on SeparatorFilter { + type: __typename + name + } + } + } + } + } +`; + +export const BASE_MANGA_FIELDS = gql` + ${PARTIAL_SOURCE_FIELDS} + fragment BASE_MANGA_FIELDS on MangaType { + artist + author + chaptersLastFetchedAt + description + genre + id + inLibrary + inLibraryAt + initialized + lastFetchedAt + meta { + key + value + } + realUrl + source { + ...PARTIAL_SOURCE_FIELDS + } + status + thumbnailUrl + title + url + } +`; + +export const PARTIAL_MANGA_FIELDS = gql` + ${BASE_MANGA_FIELDS} + ${FULL_CATEGORY_FIELDS} + ${PARTIAL_SOURCE_FIELDS} + fragment PARTIAL_MANGA_FIELDS on MangaType { + ...BASE_MANGA_FIELDS + unreadCount + downloadCount + categories { + nodes { + ...FULL_CATEGORY_FIELDS + } + totalCount + } + chapters { + totalCount + } + } +`; + +export const FULL_CHAPTER_FIELDS = gql` + ${PARTIAL_MANGA_FIELDS} + fragment FULL_CHAPTER_FIELDS on ChapterType { + chapterNumber + fetchedAt + id + isBookmarked + isDownloaded + isRead + lastPageRead + lastReadAt + manga { + ...PARTIAL_MANGA_FIELDS + } + meta { + key + value + } + name + pageCount + realUrl + scanlator + sourceOrder + uploadDate + url + } +`; + +export const FULL_MANGA_FIELDS = gql` + ${PARTIAL_MANGA_FIELDS} + ${FULL_CHAPTER_FIELDS} + fragment FULL_MANGA_FIELDS on MangaType { + ...PARTIAL_MANGA_FIELDS + lastReadChapter { + ...FULL_CHAPTER_FIELDS + } + } +`; + +export const FULL_EXTENSION_FIELDS = gql` + fragment FULL_EXTENSION_FIELDS on ExtensionType { + apkName + hasUpdate + iconUrl + isInstalled + isNsfw + isObsolete + lang + name + pkgName + versionCode + versionName + } +`; + +export const FULL_DOWNLOAD_STATUS = gql` + ${FULL_CHAPTER_FIELDS} + fragment FULL_DOWNLOAD_STATUS on DownloadStatus { + queue { + chapter { + ...FULL_CHAPTER_FIELDS + } + progress + state + tries + } + state + } +`; + +export const PARTIAL_UPDATER_STATUS = gql` + fragment PARTIAL_UPDATER_STATUS on UpdateStatus { + isRunning + } +`; + +export const FULL_UPDATER_STATUS = gql` + ${FULL_MANGA_FIELDS} + ${PARTIAL_UPDATER_STATUS} + ${FULL_CATEGORY_FIELDS} + fragment FULL_UPDATER_STATUS on UpdateStatus { + ...PARTIAL_UPDATER_STATUS + completeJobs { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + totalCount + } + } + failedJobs { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + totalCount + } + } + pendingJobs { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + totalCount + } + } + runningJobs { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + totalCount + } + } + skippedJobs { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + totalCount + } + } + updatingCategories { + categories { + nodes { + ...FULL_CATEGORY_FIELDS + } + totalCount + } + } + skippedCategories { + categories { + nodes { + ...FULL_CATEGORY_FIELDS + } + totalCount + } + } + } +`; + +export const WEBUI_UPDATE_INFO = gql` + fragment WEBUI_UPDATE_INFO on WebUIUpdateInfo { + channel + tag + updateAvailable + } +`; + +export const WEBUI_UPDATE_STATUS = gql` + ${WEBUI_UPDATE_INFO} + fragment WEBUI_UPDATE_STATUS on WebUIUpdateStatus { + info { + ...WEBUI_UPDATE_INFO + } + progress + state + } +`; + +export const SERVER_SETTINGS = gql` + fragment SERVER_SETTINGS on SettingsType { + autoDownloadNewChapters + backupInterval + backupPath + backupTTL + backupTime + basicAuthEnabled + basicAuthPassword + basicAuthUsername + debugLogsEnabled + downloadAsCbz + downloadsPath + electronPath + excludeCompleted + excludeNotStarted + excludeUnreadChapters + globalUpdateInterval + initialOpenInBrowserEnabled + ip + localSourcePath + maxSourcesInParallel + port + socksProxyEnabled + socksProxyHost + socksProxyPort + systemTrayEnabled + webUIChannel + webUIFlavor + webUIInterface + webUIUpdateCheckInterval + } +`; diff --git a/src/lib/graphql/mutations/BackupMutation.ts b/src/lib/graphql/mutations/BackupMutation.ts new file mode 100644 index 00000000..dc4c1d5a --- /dev/null +++ b/src/lib/graphql/mutations/BackupMutation.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; + +export const CREATE_BACKUP = gql` + mutation CREATE_BACKUP($input: CreateBackupInput!) { + createBackup(input: $input) { + clientMutationId + url + } + } +`; + +export const RESTORE_BACKUP = gql` + mutation RESTORE_BACKUP($input: RestoreBackupInput!) { + restoreBackup(input: $input) { + clientMutationId + status { + mangaProgress + state + totalManga + } + } + } +`; diff --git a/src/lib/graphql/mutations/CategoryMutation.ts b/src/lib/graphql/mutations/CategoryMutation.ts new file mode 100644 index 00000000..4081829e --- /dev/null +++ b/src/lib/graphql/mutations/CategoryMutation.ts @@ -0,0 +1,105 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CATEGORY_FIELDS } from '@/lib/graphql/Fragments'; + +export const CREATE_CATEGORY = gql` + ${FULL_CATEGORY_FIELDS} + mutation CREATE_CATEGORY($input: CreateCategoryInput!) { + createCategory(input: $input) { + clientMutationId + category { + ...FULL_CATEGORY_FIELDS + } + } + } +`; + +export const DELETE_CATEGORY = gql` + ${FULL_CATEGORY_FIELDS} + mutation DELETE_CATEGORY($input: DeleteCategoryInput!) { + deleteCategory(input: $input) { + clientMutationId + category { + ...FULL_CATEGORY_FIELDS + } + } + } +`; + +export const DELETE_CATEGORY_METADATA = gql` + ${FULL_CATEGORY_FIELDS} + mutation DELETE_CATEGORY_METADATA($input: DeleteCategoryMetaInput!) { + deleteCategoryMeta(input: $input) { + clientMutationId + meta { + key + value + category { + ...FULL_CATEGORY_FIELDS + } + } + category { + ...FULL_CATEGORY_FIELDS + } + } + } +`; + +export const SET_CATEGORY_METADATA = gql` + ${FULL_CATEGORY_FIELDS} + mutation SET_CATEGORY_METADATA($input: SetCategoryMetaInput!) { + setCategoryMeta(input: $input) { + clientMutationId + meta { + key + value + category { + ...FULL_CATEGORY_FIELDS + } + } + } + } +`; + +export const UPDATE_CATEGORY = gql` + ${FULL_CATEGORY_FIELDS} + mutation UPDATE_CATEGORY($input: UpdateCategoryInput!) { + updateCategory(input: $input) { + clientMutationId + category { + ...FULL_CATEGORY_FIELDS + } + } + } +`; + +export const UPDATE_CATEGORIES = gql` + ${FULL_CATEGORY_FIELDS} + mutation UPDATE_CATEGORIES($input: UpdateCategoriesInput!) { + updateCategories(input: $input) { + clientMutationId + categories { + ...FULL_CATEGORY_FIELDS + } + } + } +`; + +export const UPDATE_CATEGORY_ORDER = gql` + ${FULL_CATEGORY_FIELDS} + mutation UPDATE_CATEGORY_ORDER($input: UpdateCategoryOrderInput!) { + updateCategoryOrder(input: $input) { + clientMutationId + categories { + ...FULL_CATEGORY_FIELDS + } + } + } +`; diff --git a/src/lib/graphql/mutations/ChapterMutation.ts b/src/lib/graphql/mutations/ChapterMutation.ts new file mode 100644 index 00000000..ecf21292 --- /dev/null +++ b/src/lib/graphql/mutations/ChapterMutation.ts @@ -0,0 +1,96 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CHAPTER_FIELDS } from '@/lib/graphql/Fragments'; + +export const DELETE_CHAPTER_METADATA = gql` + ${FULL_CHAPTER_FIELDS} + mutation DELETE_CHAPTER_METADATA($input: DeleteChapterMetaInput!) { + deleteChapterMeta(input: $input) { + clientMutationId + meta { + key + value + chapter { + ...FULL_CHAPTER_FIELDS + } + } + chapter { + ...FULL_CHAPTER_FIELDS + } + } + } +`; + +// makes the server fetch and return the pages of a chapter +export const GET_CHAPTER_PAGES_FETCH = gql` + ${FULL_CHAPTER_FIELDS} + mutation GET_CHAPTER_PAGES_FETCH($input: FetchChapterPagesInput!) { + fetchChapterPages(input: $input) { + clientMutationId + chapter { + ...FULL_CHAPTER_FIELDS + } + pages + } + } +`; + +// makes the server fetch and return the chapters of the manga +export const GET_MANGA_CHAPTERS_FETCH = gql` + ${FULL_CHAPTER_FIELDS} + mutation GET_MANGA_CHAPTERS_FETCH($input: FetchChaptersInput!) { + fetchChapters(input: $input) { + clientMutationId + chapters { + ...FULL_CHAPTER_FIELDS + } + } + } +`; + +export const SET_CHAPTER_METADATA = gql` + ${FULL_CHAPTER_FIELDS} + mutation SET_CHAPTER_METADATA($input: SetChapterMetaInput!) { + setChapterMeta(input: $input) { + clientMutationId + meta { + key + value + chapter { + ...FULL_CHAPTER_FIELDS + } + } + } + } +`; + +export const UPDATE_CHAPTER = gql` + ${FULL_CHAPTER_FIELDS} + mutation UPDATE_CHAPTER($input: UpdateChapterInput!) { + updateChapter(input: $input) { + clientMutationId + chapter { + ...FULL_CHAPTER_FIELDS + } + } + } +`; + +export const UPDATE_CHAPTERS = gql` + ${FULL_CHAPTER_FIELDS} + mutation UPDATE_CHAPTERS($input: UpdateChaptersInput!) { + updateChapters(input: $input) { + clientMutationId + chapters { + ...FULL_CHAPTER_FIELDS + } + } + } +`; diff --git a/src/lib/graphql/mutations/DownloaderMutation.ts b/src/lib/graphql/mutations/DownloaderMutation.ts new file mode 100644 index 00000000..1a8e31c5 --- /dev/null +++ b/src/lib/graphql/mutations/DownloaderMutation.ts @@ -0,0 +1,130 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CHAPTER_FIELDS, FULL_DOWNLOAD_STATUS } from '@/lib/graphql/Fragments'; + +export const CLEAR_DOWNLOADER = gql` + ${FULL_DOWNLOAD_STATUS} + mutation CLEAR_DOWNLOADER($input: ClearDownloaderInput = {}) { + clearDownloader(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const DELETE_DOWNLOADED_CHAPTER = gql` + ${FULL_CHAPTER_FIELDS} + mutation DELETE_DOWNLOADED_CHAPTER($input: DeleteDownloadedChapterInput!) { + deleteDownloadedChapter(input: $input) { + clientMutationId + chapters { + ...FULL_CHAPTER_FIELDS + } + } + } +`; + +export const DELETE_DOWNLOADED_CHAPTERS = gql` + ${FULL_CHAPTER_FIELDS} + mutation DELETE_DOWNLOADED_CHAPTERS($input: DeleteDownloadedChaptersInput!) { + deleteDownloadedChapters(input: $input) { + clientMutationId + chapters { + ...FULL_CHAPTER_FIELDS + } + } + } +`; + +export const DEQUEUE_CHAPTER_DOWNLOAD = gql` + ${FULL_DOWNLOAD_STATUS} + mutation DEQUEUE_CHAPTER_DOWNLOAD($input: DequeueChapterDownloadInput!) { + dequeueChapterDownload(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const DEQUEUE_CHAPTER_DOWNLOADS = gql` + ${FULL_DOWNLOAD_STATUS} + mutation DEQUEUE_CHAPTER_DOWNLOADS($input: DequeueChapterDownloadsInput!) { + dequeueChapterDownloads(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const ENQUEUE_CHAPTER_DOWNLOAD = gql` + ${FULL_DOWNLOAD_STATUS} + mutation ENQUEUE_CHAPTER_DOWNLOAD($input: EnqueueChapterDownloadInput!) { + enqueueChapterDownload(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const ENQUEUE_CHAPTER_DOWNLOADS = gql` + ${FULL_DOWNLOAD_STATUS} + mutation ENQUEUE_CHAPTER_DOWNLOADS($input: EnqueueChapterDownloadsInput!) { + enqueueChapterDownloads(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const REORDER_CHAPTER_DOWNLOAD = gql` + ${FULL_DOWNLOAD_STATUS} + mutation REORDER_CHAPTER_DOWNLOAD($input: ReorderChapterDownloadInput!) { + reorderChapterDownload(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const START_DOWNLOADER = gql` + ${FULL_DOWNLOAD_STATUS} + mutation START_DOWNLOADER($input: StartDownloaderInput = {}) { + startDownloader(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; + +export const STOP_DOWNLOADER = gql` + ${FULL_DOWNLOAD_STATUS} + mutation STOP_DOWNLOADER($input: StopDownloaderInput = {}) { + stopDownloader(input: $input) { + clientMutationId + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } + } +`; diff --git a/src/lib/graphql/mutations/ExtensionMutation.ts b/src/lib/graphql/mutations/ExtensionMutation.ts new file mode 100644 index 00000000..0277a255 --- /dev/null +++ b/src/lib/graphql/mutations/ExtensionMutation.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_EXTENSION_FIELDS } from '@/lib/graphql/Fragments'; + +// makes the server fetch and return the latest extensions +export const GET_EXTENSIONS_FETCH = gql` + ${FULL_EXTENSION_FIELDS} + mutation GET_EXTENSIONS_FETCH($input: FetchExtensionsInput = {}) { + fetchExtensions(input: $input) { + clientMutationId + extensions { + ...FULL_EXTENSION_FIELDS + } + } + } +`; + +export const UPDATE_EXTENSION = gql` + ${FULL_EXTENSION_FIELDS} + mutation UPDATE_EXTENSION($input: UpdateExtensionInput!) { + updateExtension(input: $input) { + clientMutationId + extension { + ...FULL_EXTENSION_FIELDS + } + } + } +`; + +export const UPDATE_EXTENSIONS = gql` + ${FULL_EXTENSION_FIELDS} + mutation UPDATE_EXTENSIONS($input: UpdateExtensionsInput!) { + updateExtensions(input: $input) { + clientMutationId + extensions { + ...FULL_EXTENSION_FIELDS + } + } + } +`; + +export const INSTALL_EXTERNAL_EXTENSION = gql` + ${FULL_EXTENSION_FIELDS} + mutation INSTALL_EXTERNAL_EXTENSION($file: Upload!) { + installExternalExtension(input: { extensionFile: $file }) { + extension { + ...FULL_EXTENSION_FIELDS + } + clientMutationId + } + } +`; diff --git a/src/lib/graphql/mutations/GlobalMetadataMutation.ts b/src/lib/graphql/mutations/GlobalMetadataMutation.ts new file mode 100644 index 00000000..c02f72ba --- /dev/null +++ b/src/lib/graphql/mutations/GlobalMetadataMutation.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { GLOBAL_METADATA } from '@/lib/graphql/Fragments'; + +export const DELETE_GLOBAL_METADATA = gql` + ${GLOBAL_METADATA} + mutation DELETE_GLOBAL_METADATA($input: DeleteGlobalMetaInput!) { + deleteGlobalMeta(input: $input) { + clientMutationId + meta { + ...GLOBAL_METADATA + } + } + } +`; + +export const SET_GLOBAL_METADATA = gql` + ${GLOBAL_METADATA} + mutation SET_GLOBAL_METADATA($input: SetGlobalMetaInput!) { + setGlobalMeta(input: $input) { + clientMutationId + meta { + ...GLOBAL_METADATA + } + } + } +`; diff --git a/src/lib/graphql/mutations/MangaMutation.ts b/src/lib/graphql/mutations/MangaMutation.ts new file mode 100644 index 00000000..8ff59d2c --- /dev/null +++ b/src/lib/graphql/mutations/MangaMutation.ts @@ -0,0 +1,106 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_MANGA_FIELDS } from '@/lib/graphql/Fragments'; + +export const DELETE_MANGA_METADATA = gql` + ${FULL_MANGA_FIELDS} + mutation DELETE_MANGA_METADATA($input: DeleteMangaMetaInput!) { + deleteMangaMeta(input: $input) { + clientMutationId + meta { + key + value + manga { + ...FULL_MANGA_FIELDS + } + } + manga { + ...FULL_MANGA_FIELDS + } + } + } +`; + +// makes the server fetch and return the manga +export const GET_MANGA_FETCH = gql` + ${FULL_MANGA_FIELDS} + mutation GET_MANGA_FETCH($input: FetchMangaInput!) { + fetchManga(input: $input) { + clientMutationId + manga { + ...FULL_MANGA_FIELDS + } + } + } +`; + +export const SET_MANGA_METADATA = gql` + ${FULL_MANGA_FIELDS} + mutation SET_MANGA_METADATA($input: SetMangaMetaInput!) { + setMangaMeta(input: $input) { + clientMutationId + meta { + key + value + manga { + ...FULL_MANGA_FIELDS + } + } + } + } +`; + +export const UPDATE_MANGA = gql` + ${FULL_MANGA_FIELDS} + mutation UPDATE_MANGA($input: UpdateMangaInput!) { + updateManga(input: $input) { + clientMutationId + manga { + ...FULL_MANGA_FIELDS + } + } + } +`; + +export const UPDATE_MANGA_CATEGORIES = gql` + ${FULL_MANGA_FIELDS} + mutation UPDATE_MANGA_CATEGORIES($input: UpdateMangaCategoriesInput!) { + updateMangaCategories(input: $input) { + clientMutationId + manga { + ...FULL_MANGA_FIELDS + } + } + } +`; + +export const UPDATE_MANGAS = gql` + ${FULL_MANGA_FIELDS} + mutation UPDATE_MANGAS($input: UpdateMangasInput!) { + updateMangas(input: $input) { + clientMutationId + mangas { + ...FULL_MANGA_FIELDS + } + } + } +`; + +export const UPDATE_MANGAS_CATEGORIES = gql` + ${FULL_MANGA_FIELDS} + mutation UPDATE_MANGAS_CATEGORIES($input: UpdateMangasCategoriesInput!) { + updateMangasCategories(input: $input) { + clientMutationId + mangas { + ...FULL_MANGA_FIELDS + } + } + } +`; diff --git a/src/lib/graphql/mutations/ServerInfoMutation.ts b/src/lib/graphql/mutations/ServerInfoMutation.ts new file mode 100644 index 00000000..c040069b --- /dev/null +++ b/src/lib/graphql/mutations/ServerInfoMutation.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { WEBUI_UPDATE_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const UPDATE_WEBUI = gql` + ${WEBUI_UPDATE_STATUS} + mutation UPDATE_WEBUI($input: WebUIUpdateInput = {}) { + updateWebUI(input: $input) { + clientMutationId + updateStatus { + ...WEBUI_UPDATE_STATUS + } + } + } +`; diff --git a/src/lib/graphql/mutations/SettingsMutation.ts b/src/lib/graphql/mutations/SettingsMutation.ts new file mode 100644 index 00000000..df121056 --- /dev/null +++ b/src/lib/graphql/mutations/SettingsMutation.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { SERVER_SETTINGS } from '@/lib/graphql/Fragments'; + +export const RESET_SERVER_SETTINGS = gql` + ${SERVER_SETTINGS} + mutation RESET_SERVER_SETTINGS($input: ResetSettingsInput!) { + resetSettings(input: $input) { + clientMutationId + settings { + ...SERVER_SETTINGS + } + } + } +`; + +export const UPDATE_SERVER_SETTINGS = gql` + ${SERVER_SETTINGS} + mutation UPDATE_SERVER_SETTINGS($input: SetSettingsInput!) { + setSettings(input: $input) { + clientMutationId + settings { + ...SERVER_SETTINGS + } + } + } +`; diff --git a/src/lib/graphql/mutations/SourceMutation.ts b/src/lib/graphql/mutations/SourceMutation.ts new file mode 100644 index 00000000..f8a8a1e3 --- /dev/null +++ b/src/lib/graphql/mutations/SourceMutation.ts @@ -0,0 +1,35 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_MANGA_FIELDS, FULL_SOURCE_FIELDS } from '@/lib/graphql/Fragments'; + +export const GET_SOURCE_MANGAS_FETCH = gql` + ${FULL_MANGA_FIELDS} + mutation GET_SOURCE_MANGAS_FETCH($input: FetchSourceMangaInput!) { + fetchSourceManga(input: $input) { + clientMutationId + hasNextPage + mangas { + ...FULL_MANGA_FIELDS + } + } + } +`; + +export const UPDATE_SOURCE_PREFERENCES = gql` + ${FULL_SOURCE_FIELDS} + mutation UPDATE_SOURCE_PREFERENCES($input: UpdateSourcePreferenceInput!) { + updateSourcePreference(input: $input) { + clientMutationId + source { + ...FULL_SOURCE_FIELDS + } + } + } +`; diff --git a/src/lib/graphql/mutations/UpdaterMutation.ts b/src/lib/graphql/mutations/UpdaterMutation.ts new file mode 100644 index 00000000..c4011433 --- /dev/null +++ b/src/lib/graphql/mutations/UpdaterMutation.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { PARTIAL_UPDATER_STATUS } from '@/lib/graphql/Fragments'; + +export const UPDATE_CATEGORY_MANGAS = gql` + ${PARTIAL_UPDATER_STATUS} + mutation UPDATE_CATEGORY_MANGAS($input: UpdateCategoryMangaInput!) { + updateCategoryManga(input: $input) { + clientMutationId + updateStatus { + ...PARTIAL_UPDATER_STATUS + } + } + } +`; + +export const UPDATE_LIBRARY_MANGAS = gql` + ${PARTIAL_UPDATER_STATUS} + mutation UPDATE_LIBRARY_MANGAS($input: UpdateLibraryMangaInput = {}) { + updateLibraryManga(input: $input) { + clientMutationId + updateStatus { + ...PARTIAL_UPDATER_STATUS + } + } + } +`; + +export const STOP_UPDATER = gql` + mutation STOP_UPDATER($input: UpdateStopInput = {}) { + updateStop(input: $input) { + clientMutationId + } + } +`; diff --git a/src/lib/graphql/queries/BackupQuery.ts b/src/lib/graphql/queries/BackupQuery.ts new file mode 100644 index 00000000..8d09c94c --- /dev/null +++ b/src/lib/graphql/queries/BackupQuery.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; + +export const VALIDATE_BACKUP = gql` + query VALIDATE_BACKUP($input: ValidateBackupInput!) { + validateBackup(input: $input) { + missingSources { + id + name + } + } + } +`; + +export const GET_RESTORE_STATUS = gql` + query GET_RESTORE_STATUS { + restoreStatus { + mangaProgress + state + totalManga + } + } +`; diff --git a/src/lib/graphql/queries/CategoryQuery.ts b/src/lib/graphql/queries/CategoryQuery.ts new file mode 100644 index 00000000..8398cc8d --- /dev/null +++ b/src/lib/graphql/queries/CategoryQuery.ts @@ -0,0 +1,73 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CATEGORY_FIELDS, FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; + +export const GET_CATEGORIES = gql` + ${FULL_CATEGORY_FIELDS} + ${PAGE_INFO} + query GET_CATEGORIES( + $after: Cursor + $before: Cursor + $condition: CategoryConditionInput + $filter: CategoryFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: CategoryOrderBy + $orderByType: SortOrder + ) { + categories( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...FULL_CATEGORY_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; + +export const GET_CATEGORY = gql` + ${FULL_CATEGORY_FIELDS} + query GET_CATEGORY($id: Int!) { + category(id: $id) { + ...FULL_CATEGORY_FIELDS + } + } +`; + +export const GET_CATEGORY_MANGAS = gql` + ${FULL_MANGA_FIELDS} + ${PAGE_INFO} + query GET_CATEGORY_MANGAS($id: Int!) { + category(id: $id) { + mangas { + nodes { + ...FULL_MANGA_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } + } +`; diff --git a/src/lib/graphql/queries/ChapterQuery.ts b/src/lib/graphql/queries/ChapterQuery.ts new file mode 100644 index 00000000..89e88917 --- /dev/null +++ b/src/lib/graphql/queries/ChapterQuery.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CHAPTER_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; + +// returns the current chapter from the database +export const GET_CHAPTER = gql` + ${FULL_CHAPTER_FIELDS} + query GET_CHAPTER($id: Int!) { + chapter(id: $id) { + ...FULL_CHAPTER_FIELDS + } + } +`; + +// returns the current chapters from the database +export const GET_CHAPTERS = gql` + ${FULL_CHAPTER_FIELDS} + ${PAGE_INFO} + query GET_CHAPTERS( + $after: Cursor + $before: Cursor + $condition: ChapterConditionInput + $filter: ChapterFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: ChapterOrderBy + $orderByType: SortOrder + ) { + chapters( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...FULL_CHAPTER_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; diff --git a/src/lib/graphql/queries/DownloaderQuery.ts b/src/lib/graphql/queries/DownloaderQuery.ts new file mode 100644 index 00000000..d67cb9a6 --- /dev/null +++ b/src/lib/graphql/queries/DownloaderQuery.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_DOWNLOAD_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const GET_DOWNLOAD_STATUS = gql` + ${FULL_DOWNLOAD_STATUS} + query GET_DOWNLOAD_STATUS { + downloadStatus { + ...FULL_DOWNLOAD_STATUS + } + } +`; diff --git a/src/lib/graphql/queries/ExtensionQuery.ts b/src/lib/graphql/queries/ExtensionQuery.ts new file mode 100644 index 00000000..16d4184d --- /dev/null +++ b/src/lib/graphql/queries/ExtensionQuery.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_EXTENSION_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; + +// returns the current extension from the database +export const GET_EXTENSION = gql` + ${FULL_EXTENSION_FIELDS} + query GET_EXTENSION($pkgName: String!) { + extension(pkgName: $pkgName) { + ...FULL_EXTENSION_FIELDS + } + } +`; + +// returns the current extensions from the database +export const GET_EXTENSIONS = gql` + ${FULL_EXTENSION_FIELDS} + ${PAGE_INFO} + query GET_EXTENSIONS( + $after: Cursor + $before: Cursor + $condition: ExtensionConditionInput + $filter: ExtensionFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: ExtensionOrderBy + $orderByType: SortOrder + ) { + extensions( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...FULL_EXTENSION_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; diff --git a/src/lib/graphql/queries/GlobalMetadataQuery.ts b/src/lib/graphql/queries/GlobalMetadataQuery.ts new file mode 100644 index 00000000..cc3b69c4 --- /dev/null +++ b/src/lib/graphql/queries/GlobalMetadataQuery.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { GLOBAL_METADATA, PAGE_INFO } from '@/lib/graphql/Fragments.ts'; + +export const GET_GLOBAL_METADATA = gql` + ${GLOBAL_METADATA} + query GET_GLOBAL_METADATA($key: String!) { + meta(key: $key) { + ...GLOBAL_METADATA + } + } +`; + +export const GET_GLOBAL_METADATAS = gql` + ${GLOBAL_METADATA} + ${PAGE_INFO} + query GET_GLOBAL_METADATAS( + $after: Cursor + $before: Cursor + $condition: MetaConditionInput + $filter: MetaFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: MetaOrderBy + $orderByType: SortOrder + ) { + metas( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...GLOBAL_METADATA + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; diff --git a/src/lib/graphql/queries/MangaQuery.ts b/src/lib/graphql/queries/MangaQuery.ts new file mode 100644 index 00000000..f4d73e39 --- /dev/null +++ b/src/lib/graphql/queries/MangaQuery.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_CHAPTER_FIELDS, FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; + +// returns the current manga from the database +export const GET_MANGA = gql` + ${FULL_MANGA_FIELDS} + ${FULL_CHAPTER_FIELDS} + query GET_MANGA($id: Int!) { + manga(id: $id) { + ...FULL_MANGA_FIELDS + } + } +`; + +// returns the current manga from the database +export const GET_MANGAS = gql` + ${FULL_MANGA_FIELDS} + ${FULL_CHAPTER_FIELDS} + ${PAGE_INFO} + query GET_MANGAS( + $after: Cursor + $before: Cursor + $condition: MangaConditionInput + $filter: MangaFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: MangaOrderBy + $orderByType: SortOrder + ) { + mangas( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...FULL_MANGA_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; diff --git a/src/lib/graphql/queries/ServerInfoQuery.ts b/src/lib/graphql/queries/ServerInfoQuery.ts new file mode 100644 index 00000000..8d10ea2f --- /dev/null +++ b/src/lib/graphql/queries/ServerInfoQuery.ts @@ -0,0 +1,52 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { WEBUI_UPDATE_INFO, WEBUI_UPDATE_STATUS } from '@/lib/graphql/Fragments'; + +export const GET_ABOUT = gql` + query GET_ABOUT { + about { + buildTime + buildType + discord + github + name + revision + version + } + } +`; + +export const CHECK_FOR_SERVER_UPDATES = gql` + query CHECK_FOR_SERVER_UPDATES { + checkForServerUpdates { + channel + tag + url + } + } +`; + +export const CHECK_FOR_WEBUI_UPDATE = gql` + ${WEBUI_UPDATE_INFO} + query CHECK_FOR_WEBUI_UPDATE { + checkForWebUIUpdate { + ...WEBUI_UPDATE_INFO + } + } +`; + +export const GET_WEBUI_UPDATE_STATUS = gql` + ${WEBUI_UPDATE_STATUS} + query GET_WEBUI_UPDATE_STATUS { + getWebUIUpdateStatus { + ...WEBUI_UPDATE_STATUS + } + } +`; diff --git a/src/lib/graphql/queries/SettingsQuery.ts b/src/lib/graphql/queries/SettingsQuery.ts new file mode 100644 index 00000000..227f798e --- /dev/null +++ b/src/lib/graphql/queries/SettingsQuery.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { SERVER_SETTINGS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const GET_SERVER_SETTINGS = gql` + ${SERVER_SETTINGS} + query GET_SERVER_SETTINGS { + settings { + ...SERVER_SETTINGS + } + } +`; diff --git a/src/lib/graphql/queries/SourceQuery.ts b/src/lib/graphql/queries/SourceQuery.ts new file mode 100644 index 00000000..6d579211 --- /dev/null +++ b/src/lib/graphql/queries/SourceQuery.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_SOURCE_FIELDS, PARTIAL_SOURCE_FIELDS } from '@/lib/graphql/Fragments'; + +export const GET_SOURCE = gql` + ${FULL_SOURCE_FIELDS} + query GET_SOURCE($id: LongString!) { + source(id: $id) { + ...FULL_SOURCE_FIELDS + } + } +`; + +export const GET_SOURCES = gql` + ${PARTIAL_SOURCE_FIELDS} + query GET_SOURCES { + sources { + nodes { + ...PARTIAL_SOURCE_FIELDS + } + } + } +`; diff --git a/src/lib/graphql/queries/UpdaterQuery.ts b/src/lib/graphql/queries/UpdaterQuery.ts new file mode 100644 index 00000000..36625519 --- /dev/null +++ b/src/lib/graphql/queries/UpdaterQuery.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_UPDATER_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const GET_UPDATE_STATUS = gql` + ${FULL_UPDATER_STATUS} + query GET_UPDATE_STATUS { + updateStatus { + ...FULL_UPDATER_STATUS + } + } +`; + +export const GET_LAST_UPDATE_TIMESTAMP = gql` + query GET_LAST_UPDATE_TIMESTAMP { + lastUpdateTimestamp { + timestamp + } + } +`; diff --git a/src/lib/graphql/subscriptions/DownloaderSubscription.ts b/src/lib/graphql/subscriptions/DownloaderSubscription.ts new file mode 100644 index 00000000..af92bcfe --- /dev/null +++ b/src/lib/graphql/subscriptions/DownloaderSubscription.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_DOWNLOAD_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const DOWNLOAD_STATUS_SUBSCRIPTION = gql` + ${FULL_DOWNLOAD_STATUS} + subscription DOWNLOAD_STATUS_SUBSCRIPTION { + downloadChanged { + ...FULL_DOWNLOAD_STATUS + } + } +`; diff --git a/src/lib/graphql/subscriptions/ServerInfoSubscription.ts b/src/lib/graphql/subscriptions/ServerInfoSubscription.ts new file mode 100644 index 00000000..e95f400f --- /dev/null +++ b/src/lib/graphql/subscriptions/ServerInfoSubscription.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { WEBUI_UPDATE_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const WEBUI_UPDATE_SUBSCRIPTION = gql` + ${WEBUI_UPDATE_STATUS} + subscription WEBUI_UPDATE_SUBSCRIPTION { + webUIUpdateStatusChange { + ...WEBUI_UPDATE_STATUS + } + } +`; diff --git a/src/lib/graphql/subscriptions/UpdaterSubscription.ts b/src/lib/graphql/subscriptions/UpdaterSubscription.ts new file mode 100644 index 00000000..d16d657a --- /dev/null +++ b/src/lib/graphql/subscriptions/UpdaterSubscription.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import gql from 'graphql-tag'; +import { FULL_UPDATER_STATUS } from '@/lib/graphql/Fragments'; + +// eslint-disable-next-line import/prefer-default-export +export const UPDATER_SUBSCRIPTION = gql` + ${FULL_UPDATER_STATUS} + subscription UPDATER_SUBSCRIPTION { + updateStatusChanged { + ...FULL_UPDATER_STATUS + } + } +`; From 1b4497db46f9fa6756dc7c93311cc4e74c54670a Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sun, 9 Jul 2023 00:06:52 +0200 Subject: [PATCH 03/47] Setup "graphql-codgen" --- .eslintignore | 1 + .eslintrc.js | 2 +- gql_codegen.ts | 37 + package.json | 7 +- tsconfig.node.json | 2 +- yarn.lock | 2380 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 2393 insertions(+), 36 deletions(-) create mode 100644 gql_codegen.ts diff --git a/.eslintignore b/.eslintignore index a9ba028c..bad9857a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ .eslintrc.js +src/lib/graphql/generated diff --git a/.eslintrc.js b/.eslintrc.js index 29228c2e..8399a281 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,7 +2,7 @@ module.exports = { extends: ['airbnb', 'airbnb-typescript', 'prettier'], plugins: ['@typescript-eslint', 'no-relative-import-paths', 'prettier', 'header'], parserOptions: { - project: ['./tsconfig.json', './tools/scripts/tsconfig.json'], + project: ['./tsconfig.json', './tsconfig.node.json', './tools/scripts/tsconfig.json'], }, overrides: [ { diff --git a/gql_codegen.ts b/gql_codegen.ts new file mode 100644 index 00000000..467b5927 --- /dev/null +++ b/gql_codegen.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import type { CodegenConfig } from '@graphql-codegen/cli'; + +const config: CodegenConfig = { + overwrite: true, + schema: 'http://localhost:4567/api/graphql', + documents: [ + 'src/lib/graphql/queries/**', + 'src/lib/graphql/mutations/**', + 'src/lib/graphql/subscriptions/**', + 'src/lib/graphql/Fragments.ts', + ], + ignoreNoDocuments: true, + generates: { + 'src/lib/graphql/generated/graphql.ts': { + plugins: ['typescript', 'typescript-operations'], + config: { + namingConvention: { + typeNames: 'change-case-all#pascalCase', + transformUnderscore: true, + }, + }, + }, + 'src/lib/graphql/generated/apollo-helpers.ts': { + plugins: ['typescript-apollo-client-helpers'], + }, + }, +}; + +export default config; diff --git a/package.json b/package.json index 15e7d7b3..db611967 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "build-zip": "cd build && rev=$(git rev-list HEAD --count) && echo r$rev > revision && zip -9 -r ../buildZip/Tachidesk-WebUI-r$rev *", "lint": "eslint src --ext .ts,.tsx,.js,.jsx", "createChangelog": "ts-node tools/scripts/createReleaseChanglog.ts", - "updateDeps": "yarn outdated && yarn upgrade && yarn syncyarnlock -s -k && yarn && git add package.json yarn.lock && git commit -m \"Update dependencies\"" + "updateDeps": "yarn outdated && yarn upgrade && yarn syncyarnlock -s -k && yarn && git add package.json yarn.lock && git commit -m \"Update dependencies\"", + "gql:codegen": "graphql-codegen --config gql_codegen.ts" }, "browserslist": { "production": [ @@ -51,6 +52,10 @@ "vite-tsconfig-paths": "^4.2.1" }, "devDependencies": { + "@graphql-codegen/cli": "^5.0.0", + "@graphql-codegen/client-preset": "^4.1.0", + "@graphql-codegen/typescript-apollo-client-helpers": "^2.2.6", + "@graphql-codegen/typescript-operations": "^4.0.1", "@types/apollo-upload-client": "^17.0.2", "@types/node": "^20.6.2", "@types/react": "^18.2.21", diff --git a/tsconfig.node.json b/tsconfig.node.json index 6dae8e70..e9ec28b1 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -8,6 +8,6 @@ }, "include": [ "vite.config.ts", - "vite.config.ts" + "gql_codegen.ts" ] } diff --git a/yarn.lock b/yarn.lock index b83e9ef8..69fa2542 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,14 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@apollo/client@^3.7.0", "@apollo/client@^3.8.1": version "3.8.3" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.8.3.tgz#7cd23307bbc788a0a9eda51e6a76f32db8282933" @@ -26,7 +34,37 @@ tslib "^2.3.0" zen-observable-ts "^1.2.5" -"@babel/code-frame@^7.0.0": +"@ardatan/relay-compiler@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz#2e4cca43088e807adc63450e8cab037020e91106" + integrity sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q== + dependencies: + "@babel/core" "^7.14.0" + "@babel/generator" "^7.14.0" + "@babel/parser" "^7.14.0" + "@babel/runtime" "^7.0.0" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.0.0" + babel-preset-fbjs "^3.4.0" + chalk "^4.0.0" + fb-watchman "^2.0.0" + fbjs "^3.0.0" + glob "^7.1.1" + immutable "~3.7.6" + invariant "^2.2.4" + nullthrows "^1.1.1" + relay-runtime "12.0.0" + signedsource "^1.0.0" + yargs "^15.3.1" + +"@ardatan/sync-fetch@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz#3385d3feedceb60a896518a1db857ec1e945348f" + integrity sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA== + dependencies: + node-fetch "^2.6.1" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== @@ -34,13 +72,162 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/helper-module-imports@^7.16.7": +"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== + +"@babel/core@^7.14.0", "@babel/core@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7" + integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.22.20" + "@babel/helpers" "^7.22.15" + "@babel/parser" "^7.22.16" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.20" + "@babel/types" "^7.22.19" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.14.0", "@babel/generator@^7.18.13", "@babel/generator@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" + integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== + dependencies: + "@babel/types" "^7.22.15" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.15" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.18.6": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" + integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz#b95a144896f6d491ca7863576f820f3628818621" + integrity sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== dependencies: "@babel/types" "^7.22.15" +"@babel/helper-module-transforms@^7.22.15", "@babel/helper-module-transforms@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e" + integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" + integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" @@ -51,6 +238,20 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== + +"@babel/helpers@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" + integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.15" + "@babel/types" "^7.22.15" + "@babel/highlight@^7.22.13": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" @@ -60,14 +261,258 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.7", "@babel/runtime@^7.22.15", "@babel/runtime@^7.22.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16": + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== + +"@babel/plugin-proposal-class-properties@^7.0.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" + integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.20.7" + +"@babel/plugin-syntax-class-properties@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz#163b820b9e7696ce134df3ee716d9c0c98035859" + integrity sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-assertions@^7.20.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-transform-arrow-functions@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz#494eb82b87b5f8b1d8f6f28ea74078ec0a10a841" + integrity sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-classes@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz#aaf4753aee262a232bbc95451b4bdf9599c65a0b" + integrity sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz#e7404ea5bb3387073b9754be654eecb578324694" + integrity sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz#0bb17110c7bf5b35a60754b2f00c58302381dee2" + integrity sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-flow" "^7.22.5" + +"@babel/plugin-transform-for-of@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz#f64b4ccc3a4f131a996388fae7680b472b306b29" + integrity sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-literals@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-member-expression-literals@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz#b11810117ed4ee7691b29bd29fd9f3f98276034f" + integrity sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg== + dependencies: + "@babel/helper-module-transforms" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.7": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz#719ca82a01d177af358df64a514d64c2e3edb114" + integrity sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-property-literals@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz#3c4326f9fce31c7968d6cb9debcaf32d9e279a2b" + integrity sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz#7e6266d88705d7c49f11c98db8b9464531289cd6" + integrity sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.22.5" + "@babel/types" "^7.22.15" + +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.0.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.7", "@babel/runtime@^7.22.15", "@babel/runtime@^7.22.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA== dependencies: regenerator-runtime "^0.14.0" -"@babel/types@^7.22.15": +"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.22.15", "@babel/template@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9" + integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.16" + "@babel/types" "^7.22.19" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.8", "@babel/types@^7.18.13", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5": version "7.22.19" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== @@ -364,7 +809,508 @@ resolved "https://registry.yarnpkg.com/@fontsource/roboto/-/roboto-5.0.8.tgz#613b477a56f21b5705db1a67e995c033ef317f76" integrity sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA== -"@graphql-typed-document-node/core@^3.1.1": +"@graphql-codegen/add@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-5.0.0.tgz#578ebaf4fa87c1e934c381cd679bcedcf79feaba" + integrity sha512-ynWDOsK2yxtFHwcJTB9shoSkUd7YXd6ZE57f0nk7W5cu/nAgxZZpEsnTPEpZB/Mjf14YRGe2uJHQ7AfElHjqUQ== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + tslib "~2.5.0" + +"@graphql-codegen/cli@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-5.0.0.tgz#761dcf08cfee88bbdd9cdf8097b2343445ec6f0a" + integrity sha512-A7J7+be/a6e+/ul2KI5sfJlpoqeqwX8EzktaKCeduyVKgOLA6W5t+NUGf6QumBDXU8PEOqXk3o3F+RAwCWOiqA== + dependencies: + "@babel/generator" "^7.18.13" + "@babel/template" "^7.18.10" + "@babel/types" "^7.18.13" + "@graphql-codegen/core" "^4.0.0" + "@graphql-codegen/plugin-helpers" "^5.0.1" + "@graphql-tools/apollo-engine-loader" "^8.0.0" + "@graphql-tools/code-file-loader" "^8.0.0" + "@graphql-tools/git-loader" "^8.0.0" + "@graphql-tools/github-loader" "^8.0.0" + "@graphql-tools/graphql-file-loader" "^8.0.0" + "@graphql-tools/json-file-loader" "^8.0.0" + "@graphql-tools/load" "^8.0.0" + "@graphql-tools/prisma-loader" "^8.0.0" + "@graphql-tools/url-loader" "^8.0.0" + "@graphql-tools/utils" "^10.0.0" + "@whatwg-node/fetch" "^0.8.0" + chalk "^4.1.0" + cosmiconfig "^8.1.3" + debounce "^1.2.0" + detect-indent "^6.0.0" + graphql-config "^5.0.2" + inquirer "^8.0.0" + is-glob "^4.0.1" + jiti "^1.17.1" + json-to-pretty-yaml "^1.2.2" + listr2 "^4.0.5" + log-symbols "^4.0.0" + micromatch "^4.0.5" + shell-quote "^1.7.3" + string-env-interpolation "^1.0.1" + ts-log "^2.2.3" + tslib "^2.4.0" + yaml "^2.3.1" + yargs "^17.0.0" + +"@graphql-codegen/client-preset@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/client-preset/-/client-preset-4.1.0.tgz#81becd32b78b207b0e966876900537ec172d8df1" + integrity sha512-/3Ymb/fjxIF1+HGmaI1YwSZbWsrZAWMSQjh3dU425eBjctjsVQ6gzGRr+l/gE5F1mtmCf+vlbTAT03heAc/QIw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/template" "^7.20.7" + "@graphql-codegen/add" "^5.0.0" + "@graphql-codegen/gql-tag-operations" "4.0.1" + "@graphql-codegen/plugin-helpers" "^5.0.1" + "@graphql-codegen/typed-document-node" "^5.0.1" + "@graphql-codegen/typescript" "^4.0.1" + "@graphql-codegen/typescript-operations" "^4.0.1" + "@graphql-codegen/visitor-plugin-common" "^4.0.1" + "@graphql-tools/documents" "^1.0.0" + "@graphql-tools/utils" "^10.0.0" + "@graphql-typed-document-node/core" "3.2.0" + tslib "~2.5.0" + +"@graphql-codegen/core@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-4.0.0.tgz#b29c911746a532a675e33720acb4eb2119823e01" + integrity sha512-JAGRn49lEtSsZVxeIlFVIRxts2lWObR+OQo7V2LHDJ7ohYYw3ilv7nJ8pf8P4GTg/w6ptcYdSdVVdkI8kUHB/Q== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-tools/schema" "^10.0.0" + "@graphql-tools/utils" "^10.0.0" + tslib "~2.5.0" + +"@graphql-codegen/gql-tag-operations@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.1.tgz#36c7d40a135b9889d7f225166be323c3d48cee87" + integrity sha512-qF6wIbBzW8BNT+wiVsBxrYOs2oYcsxQ7mRvCpfEI3HnNZMAST/uX76W8MqFEJvj4mw7NIDv7xYJAcAZIWM5LWw== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-codegen/visitor-plugin-common" "4.0.1" + "@graphql-tools/utils" "^10.0.0" + auto-bind "~4.0.0" + tslib "~2.5.0" + +"@graphql-codegen/plugin-helpers@^2.7.2": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.7.2.tgz#6544f739d725441c826a8af6a49519f588ff9bed" + integrity sha512-kln2AZ12uii6U59OQXdjLk5nOlh1pHis1R98cDZGFnfaiAbX9V3fxcZ1MMJkB7qFUymTALzyjZoXXdyVmPMfRg== + dependencies: + "@graphql-tools/utils" "^8.8.0" + change-case-all "1.0.14" + common-tags "1.8.2" + import-from "4.0.0" + lodash "~4.17.0" + tslib "~2.4.0" + +"@graphql-codegen/plugin-helpers@^5.0.0", "@graphql-codegen/plugin-helpers@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.1.tgz#e2429fcfba3f078d5aa18aa062d46c922bbb0d55" + integrity sha512-6L5sb9D8wptZhnhLLBcheSPU7Tg//DGWgc5tQBWX46KYTOTQHGqDpv50FxAJJOyFVJrveN9otWk9UT9/yfY4ww== + dependencies: + "@graphql-tools/utils" "^10.0.0" + change-case-all "1.0.15" + common-tags "1.8.2" + import-from "4.0.0" + lodash "~4.17.0" + tslib "~2.5.0" + +"@graphql-codegen/schema-ast@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-4.0.0.tgz#5d60996c87b64f81847da8fcb2d8ef50ede89755" + integrity sha512-WIzkJFa9Gz28FITAPILbt+7A8+yzOyd1NxgwFh7ie+EmO9a5zQK6UQ3U/BviirguXCYnn+AR4dXsoDrSrtRA1g== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-tools/utils" "^10.0.0" + tslib "~2.5.0" + +"@graphql-codegen/typed-document-node@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.1.tgz#ac90cf67c61554f63ec100d6076b47c9f0b18b27" + integrity sha512-VFkhCuJnkgtbbgzoCAwTdJe2G1H6sd3LfCrDqWUrQe53y2ukfSb5Ov1PhAIkCBStKCMQBUY9YgGz9GKR40qQ8g== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-codegen/visitor-plugin-common" "4.0.1" + auto-bind "~4.0.0" + change-case-all "1.0.15" + tslib "~2.5.0" + +"@graphql-codegen/typescript-apollo-client-helpers@^2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-apollo-client-helpers/-/typescript-apollo-client-helpers-2.2.6.tgz#a5a7595fe426bbede4a3946dcac564280c6b641b" + integrity sha512-WEWtjg2D/Clmep7fflKmt6o70rZj/Mqf4ywIO5jF/PI91OHpKhLFM2aWm1ythkqALwQ6wJIFlAjdYqz/EOVYdQ== + dependencies: + "@graphql-codegen/plugin-helpers" "^2.7.2" + "@graphql-codegen/visitor-plugin-common" "2.13.1" + auto-bind "~4.0.0" + change-case-all "1.0.14" + tslib "~2.4.0" + +"@graphql-codegen/typescript-operations@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz#930af3e2d2ae8ff06de696291be28fe7046a2fef" + integrity sha512-GpUWWdBVUec/Zqo23aFLBMrXYxN2irypHqDcKjN78JclDPdreasAEPcIpMfqf4MClvpmvDLy4ql+djVAwmkjbw== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-codegen/typescript" "^4.0.1" + "@graphql-codegen/visitor-plugin-common" "4.0.1" + auto-bind "~4.0.0" + tslib "~2.5.0" + +"@graphql-codegen/typescript@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-4.0.1.tgz#7481d68f59bea802dd10e278dce73c8a1552b2a4" + integrity sha512-3YziQ21dCVdnHb+Us1uDb3pA6eG5Chjv0uTK+bt9dXeMlwYBU8MbtzvQTo4qvzWVC1AxSOKj0rgfNu1xCXqJyA== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-codegen/schema-ast" "^4.0.0" + "@graphql-codegen/visitor-plugin-common" "4.0.1" + auto-bind "~4.0.0" + tslib "~2.5.0" + +"@graphql-codegen/visitor-plugin-common@2.13.1": + version "2.13.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.1.tgz#2228660f6692bcdb96b1f6d91a0661624266b76b" + integrity sha512-mD9ufZhDGhyrSaWQGrU1Q1c5f01TeWtSWy/cDwXYjJcHIj1Y/DG2x0tOflEfCvh5WcnmHNIw4lzDsg1W7iFJEg== + dependencies: + "@graphql-codegen/plugin-helpers" "^2.7.2" + "@graphql-tools/optimize" "^1.3.0" + "@graphql-tools/relay-operation-optimizer" "^6.5.0" + "@graphql-tools/utils" "^8.8.0" + auto-bind "~4.0.0" + change-case-all "1.0.14" + dependency-graph "^0.11.0" + graphql-tag "^2.11.0" + parse-filepath "^1.0.2" + tslib "~2.4.0" + +"@graphql-codegen/visitor-plugin-common@4.0.1", "@graphql-codegen/visitor-plugin-common@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.0.1.tgz#64e293728b3c186f6767141e41fcdb310e50d367" + integrity sha512-Bi/1z0nHg4QMsAqAJhds+ForyLtk7A3HQOlkrZNm3xEkY7lcBzPtiOTLBtvziwopBsXUxqeSwVjOOFPLS5Yw1Q== + dependencies: + "@graphql-codegen/plugin-helpers" "^5.0.0" + "@graphql-tools/optimize" "^2.0.0" + "@graphql-tools/relay-operation-optimizer" "^7.0.0" + "@graphql-tools/utils" "^10.0.0" + auto-bind "~4.0.0" + change-case-all "1.0.15" + dependency-graph "^0.11.0" + graphql-tag "^2.11.0" + parse-filepath "^1.0.2" + tslib "~2.5.0" + +"@graphql-tools/apollo-engine-loader@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489" + integrity sha512-axQTbN5+Yxs1rJ6cWQBOfw3AEeC+fvIuZSfJLPLLvFJLj4pUm9fhxey/g6oQZAAQJqKPfw+tLDUQvnfvRK8Kmg== + dependencies: + "@ardatan/sync-fetch" "^0.0.1" + "@graphql-tools/utils" "^10.0.0" + "@whatwg-node/fetch" "^0.9.0" + tslib "^2.4.0" + +"@graphql-tools/batch-execute@^9.0.1": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-9.0.2.tgz#5ac3257501e7941fad40661bb5e1110d6312f58b" + integrity sha512-Y2uwdZI6ZnatopD/SYfZ1eGuQFI7OU2KGZ2/B/7G9ISmgMl5K+ZZWz/PfIEXeiHirIDhyk54s4uka5rj2xwKqQ== + dependencies: + "@graphql-tools/utils" "^10.0.5" + dataloader "^2.2.2" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-tools/code-file-loader@^8.0.0": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-8.0.2.tgz#224b9ce29d9229c52d8bd7b6d976038f4ea5d3f4" + integrity sha512-AKNpkElUL2cWocYpC4DzNEpo6qJw8Lp+L3bKQ/mIfmbsQxgLz5uve6zHBMhDaFPdlwfIox41N3iUSvi77t9e8A== + dependencies: + "@graphql-tools/graphql-tag-pluck" "8.0.2" + "@graphql-tools/utils" "^10.0.0" + globby "^11.0.3" + tslib "^2.4.0" + unixify "^1.0.0" + +"@graphql-tools/delegate@^10.0.0", "@graphql-tools/delegate@^10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-10.0.3.tgz#2d0e133da94ca92c24e0c7360414e5592321cf2d" + integrity sha512-Jor9oazZ07zuWkykD3OOhT/2XD74Zm6Ar0ENZMk75MDD51wB2UWUIMljtHxbJhV5A6UBC2v8x6iY0xdCGiIlyw== + dependencies: + "@graphql-tools/batch-execute" "^9.0.1" + "@graphql-tools/executor" "^1.0.0" + "@graphql-tools/schema" "^10.0.0" + "@graphql-tools/utils" "^10.0.5" + dataloader "^2.2.2" + tslib "^2.5.0" + +"@graphql-tools/documents@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/documents/-/documents-1.0.0.tgz#e3ed97197cc22ec830ca227fd7d17e86d8424bdf" + integrity sha512-rHGjX1vg/nZ2DKqRGfDPNC55CWZBMldEVcH+91BThRa6JeT80NqXknffLLEZLRUxyikCfkwMsk6xR3UNMqG0Rg== + dependencies: + lodash.sortby "^4.7.0" + tslib "^2.4.0" + +"@graphql-tools/executor-graphql-ws@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.1.0.tgz#7727159ebaa9df4dc793d0d02e74dd1ca4a7cc60" + integrity sha512-yM67SzwE8rYRpm4z4AuGtABlOp9mXXVy6sxXnTJRoYIdZrmDbKVfIY+CpZUJCqS0FX3xf2+GoHlsj7Qswaxgcg== + dependencies: + "@graphql-tools/utils" "^10.0.2" + "@types/ws" "^8.0.0" + graphql-ws "^5.14.0" + isomorphic-ws "^5.0.0" + tslib "^2.4.0" + ws "^8.13.0" + +"@graphql-tools/executor-http@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/executor-http/-/executor-http-1.0.2.tgz#d7964a6e5ec883842f9a8e3f104f93c9b8f472be" + integrity sha512-JKTB4E3kdQM2/1NEcyrVPyQ8057ZVthCV5dFJiKktqY9IdmF00M8gupFcW3jlbM/Udn78ickeUBsUzA3EouqpA== + dependencies: + "@graphql-tools/utils" "^10.0.2" + "@repeaterjs/repeater" "^3.0.4" + "@whatwg-node/fetch" "^0.9.0" + extract-files "^11.0.0" + meros "^1.2.1" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-tools/executor-legacy-ws@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.3.tgz#de04eaa816fa27f46b401e8d5c28d9c0562b4993" + integrity sha512-rr3IDeO9Dh+8u8KIro++5kzJJYPHkcrIAWzqXtN663nhInC85iW7Ko91yOYwf7ovBci/7s+4Rqe4ZRyca1LGjQ== + dependencies: + "@graphql-tools/utils" "^10.0.0" + "@types/ws" "^8.0.0" + isomorphic-ws "5.0.0" + tslib "^2.4.0" + ws "8.14.1" + +"@graphql-tools/executor@^1.0.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/executor/-/executor-1.2.0.tgz#6c45f4add765769d9820c4c4405b76957ba39c79" + integrity sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg== + dependencies: + "@graphql-tools/utils" "^10.0.0" + "@graphql-typed-document-node/core" "3.2.0" + "@repeaterjs/repeater" "^3.0.4" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-tools/git-loader@^8.0.0": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/git-loader/-/git-loader-8.0.2.tgz#d26d87e176ff0cea86e0acfe7c2072f32fd836c3" + integrity sha512-AuCB0nlPvsHh8u42zRZdlD/ZMaWP9A44yAkQUVCZir1E/LG63fsZ9svTWJ+CbusW3Hd0ZP9qpxEhlHxnd4Tlsg== + dependencies: + "@graphql-tools/graphql-tag-pluck" "8.0.2" + "@graphql-tools/utils" "^10.0.0" + is-glob "4.0.3" + micromatch "^4.0.4" + tslib "^2.4.0" + unixify "^1.0.0" + +"@graphql-tools/github-loader@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/github-loader/-/github-loader-8.0.0.tgz#683195800618364701cfea9bc6f88674486f053b" + integrity sha512-VuroArWKcG4yaOWzV0r19ElVIV6iH6UKDQn1MXemND0xu5TzrFme0kf3U9o0YwNo0kUYEk9CyFM0BYg4he17FA== + dependencies: + "@ardatan/sync-fetch" "^0.0.1" + "@graphql-tools/executor-http" "^1.0.0" + "@graphql-tools/graphql-tag-pluck" "^8.0.0" + "@graphql-tools/utils" "^10.0.0" + "@whatwg-node/fetch" "^0.9.0" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-tools/graphql-file-loader@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.0.tgz#a2026405bce86d974000455647511bf65df4f211" + integrity sha512-wRXj9Z1IFL3+zJG1HWEY0S4TXal7+s1vVhbZva96MSp0kbb/3JBF7j0cnJ44Eq0ClccMgGCDFqPFXty4JlpaPg== + dependencies: + "@graphql-tools/import" "7.0.0" + "@graphql-tools/utils" "^10.0.0" + globby "^11.0.3" + tslib "^2.4.0" + unixify "^1.0.0" + +"@graphql-tools/graphql-tag-pluck@8.0.2", "@graphql-tools/graphql-tag-pluck@^8.0.0": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.0.2.tgz#c1ce8226c951583a27765dccceea19dc5827a948" + integrity sha512-U6fE4yEHxuk/nqmPixHpw1WhqdS6aYuaV60m1bEmUmGJNbpAhaMBy01JncpvpF15yZR5LZ0UjkHg+A3Lhoc8YQ== + dependencies: + "@babel/core" "^7.22.9" + "@babel/parser" "^7.16.8" + "@babel/plugin-syntax-import-assertions" "^7.20.0" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + "@graphql-tools/utils" "^10.0.0" + tslib "^2.4.0" + +"@graphql-tools/import@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-7.0.0.tgz#a6a91a90a707d5f46bad0fd3fde2f407b548b2be" + integrity sha512-NVZiTO8o1GZs6OXzNfjB+5CtQtqsZZpQOq+Uu0w57kdUkT4RlQKlwhT8T81arEsbV55KpzkpFsOZP7J1wdmhBw== + dependencies: + "@graphql-tools/utils" "^10.0.0" + resolve-from "5.0.0" + tslib "^2.4.0" + +"@graphql-tools/json-file-loader@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-8.0.0.tgz#9b1b62902f766ef3f1c9cd1c192813ea4f48109c" + integrity sha512-ki6EF/mobBWJjAAC84xNrFMhNfnUFD6Y0rQMGXekrUgY0NdeYXHU0ZUgHzC9O5+55FslqUmAUHABePDHTyZsLg== + dependencies: + "@graphql-tools/utils" "^10.0.0" + globby "^11.0.3" + tslib "^2.4.0" + unixify "^1.0.0" + +"@graphql-tools/load@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-8.0.0.tgz#62e00f48c39b4085167a096f66ba6c21fb3fc796" + integrity sha512-Cy874bQJH0FP2Az7ELPM49iDzOljQmK1PPH6IuxsWzLSTxwTqd8dXA09dcVZrI7/LsN26heTY2R8q2aiiv0GxQ== + dependencies: + "@graphql-tools/schema" "^10.0.0" + "@graphql-tools/utils" "^10.0.0" + p-limit "3.1.0" + tslib "^2.4.0" + +"@graphql-tools/merge@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.0.0.tgz#b0a3636c82716454bff88e9bb40108b0471db281" + integrity sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q== + dependencies: + "@graphql-tools/utils" "^10.0.0" + tslib "^2.4.0" + +"@graphql-tools/optimize@^1.3.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.4.0.tgz#20d6a9efa185ef8fc4af4fd409963e0907c6e112" + integrity sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/optimize@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-2.0.0.tgz#7a9779d180824511248a50c5a241eff6e7a2d906" + integrity sha512-nhdT+CRGDZ+bk68ic+Jw1OZ99YCDIKYA5AlVAnBHJvMawSx9YQqQAIj4refNc1/LRieGiuWvhbG3jvPVYho0Dg== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/prisma-loader@^8.0.0": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/prisma-loader/-/prisma-loader-8.0.1.tgz#0a013c69b04e0779b5be15757173d458cdf94e35" + integrity sha512-bl6e5sAYe35Z6fEbgKXNrqRhXlCJYeWKBkarohgYA338/SD9eEhXtg3Cedj7fut3WyRLoQFpHzfiwxKs7XrgXg== + dependencies: + "@graphql-tools/url-loader" "^8.0.0" + "@graphql-tools/utils" "^10.0.0" + "@types/js-yaml" "^4.0.0" + "@types/json-stable-stringify" "^1.0.32" + "@whatwg-node/fetch" "^0.9.0" + chalk "^4.1.0" + debug "^4.3.1" + dotenv "^16.0.0" + graphql-request "^6.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + jose "^4.11.4" + js-yaml "^4.0.0" + json-stable-stringify "^1.0.1" + lodash "^4.17.20" + scuid "^1.1.0" + tslib "^2.4.0" + yaml-ast-parser "^0.0.43" + +"@graphql-tools/relay-operation-optimizer@^6.5.0": + version "6.5.18" + resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.18.tgz#a1b74a8e0a5d0c795b8a4d19629b654cf66aa5ab" + integrity sha512-mc5VPyTeV+LwiM+DNvoDQfPqwQYhPV/cl5jOBjTgSniyaq8/86aODfMkrE2OduhQ5E00hqrkuL2Fdrgk0w1QJg== + dependencies: + "@ardatan/relay-compiler" "12.0.0" + "@graphql-tools/utils" "^9.2.1" + tslib "^2.4.0" + +"@graphql-tools/relay-operation-optimizer@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.0.tgz#24367666af87bc5a81748de5e8e9b3c523fd4207" + integrity sha512-UNlJi5y3JylhVWU4MBpL0Hun4Q7IoJwv9xYtmAz+CgRa066szzY7dcuPfxrA7cIGgG/Q6TVsKsYaiF4OHPs1Fw== + dependencies: + "@ardatan/relay-compiler" "12.0.0" + "@graphql-tools/utils" "^10.0.0" + tslib "^2.4.0" + +"@graphql-tools/schema@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.0.tgz#7b5f6b6a59f51c927de8c9069bde4ebbfefc64b3" + integrity sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg== + dependencies: + "@graphql-tools/merge" "^9.0.0" + "@graphql-tools/utils" "^10.0.0" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-tools/url-loader@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-8.0.0.tgz#8d952d5ebb7325e587cb914aaebded3dbd078cf6" + integrity sha512-rPc9oDzMnycvz+X+wrN3PLrhMBQkG4+sd8EzaFN6dypcssiefgWKToXtRKI8HHK68n2xEq1PyrOpkjHFJB+GwA== + dependencies: + "@ardatan/sync-fetch" "^0.0.1" + "@graphql-tools/delegate" "^10.0.0" + "@graphql-tools/executor-graphql-ws" "^1.0.0" + "@graphql-tools/executor-http" "^1.0.0" + "@graphql-tools/executor-legacy-ws" "^1.0.0" + "@graphql-tools/utils" "^10.0.0" + "@graphql-tools/wrap" "^10.0.0" + "@types/ws" "^8.0.0" + "@whatwg-node/fetch" "^0.9.0" + isomorphic-ws "^5.0.0" + tslib "^2.4.0" + value-or-promise "^1.0.11" + ws "^8.12.0" + +"@graphql-tools/utils@^10.0.0", "@graphql-tools/utils@^10.0.2", "@graphql-tools/utils@^10.0.5": + version "10.0.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.0.6.tgz#8a809d6bc0df27ffe8964696f182af2383b5974b" + integrity sha512-hZMjl/BbX10iagovakgf3IiqArx8TPsotq5pwBld37uIX1JiZoSbgbCIFol7u55bh32o6cfDEiiJgfAD5fbeyQ== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + dset "^3.1.2" + tslib "^2.4.0" + +"@graphql-tools/utils@^8.8.0": + version "8.13.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.13.1.tgz#b247607e400365c2cd87ff54654d4ad25a7ac491" + integrity sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/utils@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57" + integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + tslib "^2.4.0" + +"@graphql-tools/wrap@^10.0.0": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-10.0.1.tgz#9e3d27d2723962c26c4377d5d7ab0d3038bf728c" + integrity sha512-Cw6hVrKGM2OKBXeuAGltgy4tzuqQE0Nt7t/uAqnuokSXZhMHXJUb124Bnvxc2gPZn5chfJSDafDe4Cp8ZAVJgg== + dependencies: + "@graphql-tools/delegate" "^10.0.3" + "@graphql-tools/schema" "^10.0.0" + "@graphql-tools/utils" "^10.0.0" + tslib "^2.4.0" + value-or-promise "^1.0.12" + +"@graphql-typed-document-node/core@3.2.0", "@graphql-typed-document-node/core@^3.1.1", "@graphql-typed-document-node/core@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== @@ -388,12 +1334,26 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -406,6 +1366,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@mui/base@5.0.0-beta.15": version "5.0.0-beta.15" resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.15.tgz#76bebd377cc3b7fdc80924759a4100e5319ed0f9" @@ -518,6 +1486,33 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@peculiar/asn1-schema@^2.3.6": + version "2.3.6" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz#3dd3c2ade7f702a9a94dfb395c192f5fa5d6b922" + integrity sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA== + dependencies: + asn1js "^3.0.5" + pvtsutils "^1.3.2" + tslib "^2.4.0" + +"@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + +"@peculiar/webcrypto@^1.4.0": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz#078b3e8f598e847b78683dc3ba65feb5029b93a7" + integrity sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A== + dependencies: + "@peculiar/asn1-schema" "^2.3.6" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.3.2" + tslib "^2.5.0" + webcrypto-core "^1.7.7" + "@pkgr/utils@^2.3.1": version "2.4.2" resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" @@ -540,6 +1535,11 @@ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.9.0.tgz#9033238b41c4cbe1e961eccb3f79e2c588328cf6" integrity sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA== +"@repeaterjs/repeater@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@repeaterjs/repeater/-/repeater-3.0.4.tgz#a04d63f4d1bf5540a41b01a921c9a7fddc3bd1ca" + integrity sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA== + "@swc/core-darwin-arm64@1.3.85": version "1.3.85" resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.85.tgz#f92d3c2b7f85f7dc0707e4ec06e344c96b26b476" @@ -655,17 +1655,27 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/js-yaml@^4.0.0": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.6.tgz#4b3afd5158b8749095b1f096967b6d0f838d862f" + integrity sha512-ACTuifTSIIbyksx2HTon3aFtCKWcID7/h3XEmRpDYdMCXxPbl+m9GteOJeaAkiAta/NJaSFuA7ahZ0NkwajDSw== + "@types/json-schema@^7.0.12": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== +"@types/json-stable-stringify@^1.0.32": + version "1.0.34" + resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz#c0fb25e4d957e0ee2e497c1f553d7f8bb668fd75" + integrity sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/node@^20.6.2": +"@types/node@*", "@types/node@^20.6.2": version "20.6.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== @@ -730,6 +1740,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== +"@types/ws@^8.0.0": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -834,6 +1851,57 @@ dependencies: "@swc/core" "^1.3.61" +"@whatwg-node/events@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.0.3.tgz#13a65dd4f5893f55280f766e29ae48074927acad" + integrity sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA== + +"@whatwg-node/events@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.1.1.tgz#0ca718508249419587e130da26d40e29d99b5356" + integrity sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w== + +"@whatwg-node/fetch@^0.8.0": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.8.8.tgz#48c6ad0c6b7951a73e812f09dd22d75e9fa18cae" + integrity sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg== + dependencies: + "@peculiar/webcrypto" "^1.4.0" + "@whatwg-node/node-fetch" "^0.3.6" + busboy "^1.6.0" + urlpattern-polyfill "^8.0.0" + web-streams-polyfill "^3.2.1" + +"@whatwg-node/fetch@^0.9.0": + version "0.9.13" + resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.9.13.tgz#1d084cd546b9cd425ae89cbb1252a3e47a9a2e1c" + integrity sha512-PPtMwhjtS96XROnSpowCQM85gCUG2m7AXZFw0PZlGbhzx2GK7f2iOXilfgIJ0uSlCuuGbOIzfouISkA7C4FJOw== + dependencies: + "@whatwg-node/node-fetch" "^0.4.17" + urlpattern-polyfill "^9.0.0" + +"@whatwg-node/node-fetch@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz#e28816955f359916e2d830b68a64493124faa6d0" + integrity sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA== + dependencies: + "@whatwg-node/events" "^0.0.3" + busboy "^1.6.0" + fast-querystring "^1.1.1" + fast-url-parser "^1.1.3" + tslib "^2.3.1" + +"@whatwg-node/node-fetch@^0.4.17": + version "0.4.19" + resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.4.19.tgz#29c72ff65a8e450949238612ff17a3d3717736d3" + integrity sha512-AW7/m2AuweAoSXmESrYQr/KBafueScNbn2iNO0u6xFr2JZdPmYsSm5yvAXYk6yDLv+eDmSSKrf7JnFZ0CsJIdA== + dependencies: + "@whatwg-node/events" "^0.1.0" + busboy "^1.6.0" + fast-querystring "^1.1.1" + fast-url-parser "^1.1.3" + tslib "^2.3.1" + "@wry/context@^0.7.0", "@wry/context@^0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.3.tgz#240f6dfd4db5ef54f81f6597f6714e58d4f476a1" @@ -870,6 +1938,21 @@ acorn@^8.4.1, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + dependencies: + debug "^4.3.4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -880,6 +1963,13 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -1002,11 +2092,30 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +asn1js@^3.0.1, asn1js@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" + integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== + dependencies: + pvtsutils "^1.3.2" + pvutils "^1.1.3" + tslib "^2.4.0" + ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + asynciterator.prototype@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" @@ -1019,6 +2128,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +auto-bind@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" + integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -1054,16 +2168,68 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" +babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: + version "7.0.0-beta.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" + integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== + +babel-preset-fbjs@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" + integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-member-expression-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-property-literals" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + big-integer@^1.6.44: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + bplist-parser@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" @@ -1086,6 +2252,31 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + bundle-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" @@ -1093,6 +2284,13 @@ bundle-name@^3.0.0: dependencies: run-applescript "^5.0.0" +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -1106,6 +2304,33 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-lite@^1.0.30001517: + version "1.0.30001534" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz#f24a9b2a6d39630bac5c132b5dff89b39a12e7dd" + integrity sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q== + +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1115,7 +2340,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1123,11 +2348,105 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +change-case-all@1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" + integrity sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA== + dependencies: + change-case "^4.1.2" + is-lower-case "^2.0.2" + is-upper-case "^2.0.2" + lower-case "^2.0.2" + lower-case-first "^2.0.2" + sponge-case "^1.0.1" + swap-case "^2.0.2" + title-case "^3.0.3" + upper-case "^2.0.2" + upper-case-first "^2.0.2" + +change-case-all@1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.15.tgz#de29393167fc101d646cd76b0ef23e27d09756ad" + integrity sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ== + dependencies: + change-case "^4.1.2" + is-lower-case "^2.0.2" + is-upper-case "^2.0.2" + lower-case "^2.0.2" + lower-case-first "^2.0.2" + sponge-case "^1.0.1" + swap-case "^2.0.2" + title-case "^3.0.3" + upper-case "^2.0.2" + upper-case-first "^2.0.2" + +change-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== + dependencies: + camel-case "^4.1.2" + capital-case "^1.0.4" + constant-case "^3.0.4" + dot-case "^3.0.4" + header-case "^2.0.4" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.2" + path-case "^3.0.4" + sentence-case "^3.0.4" + snake-case "^3.0.4" + tslib "^2.0.3" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.1.tgz#9c0b9dad69a6d47cbb4333c14319b060ed395a35" + integrity sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ== + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + client-only@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1137,6 +2456,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + clsx@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" @@ -1166,6 +2490,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^2.0.16: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1178,6 +2507,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +common-tags@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1188,7 +2522,16 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== -convert-source-map@^1.5.0: +constant-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case "^2.0.2" + +convert-source-map@^1.5.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -1204,11 +2547,28 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^8.1.0, cosmiconfig@^8.1.3: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1235,6 +2595,23 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== +dataloader@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" + integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== + +debounce@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -1242,12 +2619,10 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== deep-is@^0.1.3: version "0.1.4" @@ -1272,6 +2647,13 @@ default-browser@^4.0.0: execa "^7.1.1" titleize "^3.0.0" +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + define-data-property@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" @@ -1300,11 +2682,21 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +dependency-graph@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" + integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== + dequal@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +detect-indent@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -1339,6 +2731,29 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dotenv@^16.0.0: + version "16.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" + integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== + +dset@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a" + integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q== + +electron-to-chromium@^1.4.477: + version "1.4.523" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz#f82f99243c827df05c26776d49712cb284972df6" + integrity sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -1745,11 +3160,25 @@ execa@^7.1.1: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extract-files@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1781,6 +3210,20 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-querystring@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.2.tgz#a6d24937b4fc6f791b4ee31dcb6f53aeafb89f53" + integrity sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg== + dependencies: + fast-decode-uri-component "^1.0.1" + +fast-url-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== + dependencies: + punycode "^1.3.2" + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -1788,6 +3231,38 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d" + integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg== + dependencies: + cross-fetch "^3.1.5" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^1.0.35" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1814,6 +3289,14 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -1887,7 +3370,12 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -get-caller-file@^2.0.5: +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -1929,7 +3417,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3, glob@^7.1.4: +glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1941,6 +3429,11 @@ glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^13.19.0: version "13.21.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" @@ -1955,7 +3448,7 @@ globalthis@^1.0.3: dependencies: define-properties "^1.1.3" -globby@^11.1.0: +globby@^11.0.3, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -1984,13 +3477,43 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -graphql-tag@^2.12.6: +graphql-config@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-5.0.2.tgz#7e962f94ccddcc2ee0aa71d75cf4491ec5092bdb" + integrity sha512-7TPxOrlbiG0JplSZYCyxn2XQtqVhXomEjXUmWJVSS5ET1nPhOJSsIb/WTwqWhcYX6G0RlHXSj9PLtGTKmxLNGg== + dependencies: + "@graphql-tools/graphql-file-loader" "^8.0.0" + "@graphql-tools/json-file-loader" "^8.0.0" + "@graphql-tools/load" "^8.0.0" + "@graphql-tools/merge" "^9.0.0" + "@graphql-tools/url-loader" "^8.0.0" + "@graphql-tools/utils" "^10.0.0" + cosmiconfig "^8.1.0" + jiti "^1.18.2" + minimatch "^4.2.3" + string-env-interpolation "^1.0.1" + tslib "^2.4.0" + +graphql-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" + integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + cross-fetch "^3.1.5" + +graphql-tag@^2.11.0, graphql-tag@^2.12.6: version "2.12.6" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== dependencies: tslib "^2.1.0" +graphql-ws@^5.14.0: + version "5.14.0" + resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.14.0.tgz#766f249f3974fc2c48fae0d1fb20c2c4c79cd591" + integrity sha512-itrUTQZP/TgswR4GSSYuwWUzrE/w5GhbwM2GX3ic2U7aw33jgEsayfIlvaj7/GcIvZgNMzsPTrE5hqPuFUiE5g== + "graphql@14 - 16": version "16.8.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.0.tgz#374478b7f27b2dc6153c8f42c1b80157f79d79d4" @@ -2042,6 +3565,14 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +header-case@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== + dependencies: + capital-case "^1.0.4" + tslib "^2.0.3" + hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -2056,6 +3587,22 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -2080,12 +3627,29 @@ i18next@^23.5.1: dependencies: "@babel/runtime" "^7.22.5" +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0, ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.2.1: +immutable@~3.7.6: + version "3.7.6" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== + +import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -2093,11 +3657,21 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-from@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" + integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2106,11 +3680,32 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inquirer@^8.0.0: + version "8.2.6" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562" + integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^6.0.1" + internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" @@ -2120,6 +3715,21 @@ internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" @@ -2209,7 +3819,7 @@ is-generator-function@^1.0.10: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@4.0.3, is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -2223,6 +3833,18 @@ is-inside-container@^1.0.0: dependencies: is-docker "^3.0.0" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" + integrity sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ== + dependencies: + tslib "^2.0.3" + is-map@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" @@ -2258,6 +3880,13 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + is-set@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" @@ -2301,6 +3930,25 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: dependencies: which-typed-array "^1.1.11" +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" + integrity sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ== + dependencies: + tslib "^2.0.3" + is-weakmap@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" @@ -2321,6 +3969,11 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" +is-windows@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -2338,6 +3991,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isomorphic-ws@5.0.0, isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -2349,18 +4007,33 @@ iterator.prototype@^1.1.2: reflect.getprototypeof "^1.0.4" set-function-name "^2.0.1" +jiti@^1.17.1, jiti@^1.18.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" + integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== + +jose@^4.11.4: + version "4.14.6" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.14.6.tgz#94dca1d04a0ad8c6bff0998cdb51220d473cc3af" + integrity sha512-EqJPEUlZD0/CSUMubKtMaYUOtWe91tZXTWMJZoKSbLk+KtdhNdcvppH8lA9XwVu2V4Ailvsj0GBZJ2ZwDjfesQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^4.1.0: +js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -2381,6 +4054,21 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stable-stringify@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" + integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== + dependencies: + jsonify "^0.0.1" + +json-to-pretty-yaml@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz#f4cd0bd0a5e8fe1df25aaf5ba118b099fd992d5b" + integrity sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A== + dependencies: + remedial "^1.0.7" + remove-trailing-spaces "^1.0.6" + json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -2388,6 +4076,16 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -2430,6 +4128,27 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +listr2@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.5" + through "^2.3.8" + wrap-ansi "^7.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -2442,13 +4161,62 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -loose-envify@^1.1.0, loose-envify@^1.4.0: +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + +lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.0.0, log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" + integrity sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg== + dependencies: + tslib "^2.0.3" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -2461,6 +4229,11 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +map-cache@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== + memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -2476,7 +4249,12 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4: +meros@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/meros/-/meros-1.3.0.tgz#c617d2092739d55286bf618129280f362e6242f2" + integrity sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w== + +micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -2513,6 +4291,13 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.3.tgz#b4dcece1d674dee104bb0fb833ebb85a78cbbca6" + integrity sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng== + dependencies: + brace-expansion "^1.1.7" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -2528,6 +4313,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nanoid@^3.3.6: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" @@ -2538,6 +4328,38 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-fetch@^2.6.1, node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== + dependencies: + remove-trailing-separator "^1.0.1" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -2552,7 +4374,12 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -object-assign@^4.1.1: +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -2629,7 +4456,7 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.2: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -2674,13 +4501,47 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -p-limit@^3.0.2: +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@3.1.0, p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -2688,6 +4549,26 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -2695,7 +4576,16 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^5.0.0: +parse-filepath@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" + integrity sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q== + dependencies: + is-absolute "^1.0.0" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -2705,6 +4595,22 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -2730,6 +4636,18 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ== + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg== + dependencies: + path-root-regex "^0.1.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -2771,6 +4689,13 @@ prettier@^3.0.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -2785,11 +4710,28 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +pvtsutils@^1.3.2: + version "1.3.5" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.5.tgz#b8705b437b7b134cd7fd858f025a23456f1ce910" + integrity sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA== + dependencies: + tslib "^2.6.1" + +pvutils@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -2893,6 +4835,15 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + redux@^4.0.0, redux@^4.0.4: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" @@ -2926,11 +4877,45 @@ regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: define-properties "^1.2.0" set-function-name "^2.0.0" +relay-runtime@12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" + integrity sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug== + dependencies: + "@babel/runtime" "^7.0.0" + fbjs "^3.0.0" + invariant "^2.2.4" + +remedial@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remedial/-/remedial-1.0.8.tgz#a5e4fd52a0e4956adbaf62da63a5a46a78c578a0" + integrity sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg== + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== + +remove-trailing-spaces@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7" + integrity sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-from@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -2959,11 +4944,24 @@ response-iterator@^0.2.6: resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -2985,6 +4983,11 @@ run-applescript@^5.0.0: dependencies: execa "^5.0.0" +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2992,6 +4995,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^7.5.5: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-array-concat@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" @@ -3002,6 +5012,11 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -3011,6 +5026,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" @@ -3018,6 +5038,11 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" +scuid@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab" + integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== + semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -3030,11 +5055,25 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" +sentence-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + serialize-query-params@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/serialize-query-params/-/serialize-query-params-2.0.2.tgz#598a3fb9e13f4ea1c1992fbd20231aa16b31db81" integrity sha512-1chMo1dST4pFA9RDXAtF0Rbjaut4is7bzFbI1Z26IuMub68pNCILku85aYmeFhvnY//BXUPUhoRMjYcsT93J/Q== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + set-function-name@^2.0.0, set-function-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" @@ -3044,6 +5083,11 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3056,6 +5100,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -3065,16 +5114,47 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signedsource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" + integrity sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -3085,6 +5165,23 @@ source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== +sponge-case@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" + integrity sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA== + dependencies: + tslib "^2.0.3" + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +string-env-interpolation@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" + integrity sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg== + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -3136,6 +5233,13 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -3187,6 +5291,13 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swap-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" + integrity sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw== + dependencies: + tslib "^2.0.3" + swr@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.2.tgz#abcb1f9c97e10527789884169d58b878472d4c98" @@ -3221,16 +5332,35 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +through@^2.3.6, through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + tiny-invariant@^1.0.6: version "1.3.1" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +title-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" + integrity sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA== + dependencies: + tslib "^2.0.3" + titleize@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -3243,6 +5373,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-api-utils@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" @@ -3255,6 +5390,11 @@ ts-invariant@^0.10.3: dependencies: tslib "^2.1.0" +ts-log@^2.2.3: + version "2.2.5" + resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.5.tgz#aef3252f1143d11047e2cb6f7cfaac7408d96623" + integrity sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA== + ts-node@^10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -3289,11 +5429,21 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0, tslib@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@~2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + +tslib@~2.5.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" + integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -3306,6 +5456,11 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -3350,6 +5505,11 @@ typescript@^5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +ua-parser-js@^1.0.35: + version "1.0.36" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.36.tgz#a9ab6b9bd3a8efb90bb0816674b412717b7c428c" + integrity sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw== + unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -3360,11 +5520,45 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg== + +unixify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" + integrity sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg== + dependencies: + normalize-path "^2.1.1" + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -3372,6 +5566,16 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urlpattern-polyfill@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz#99f096e35eff8bf4b5a2aa7d58a1523d6ebc7ce5" + integrity sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ== + +urlpattern-polyfill@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz#bc7e386bb12fd7898b58d1509df21d3c29ab3460" + integrity sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g== + use-memo-one@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" @@ -3389,11 +5593,21 @@ use-sync-external-store@^1.2.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +value-or-promise@^1.0.11, value-or-promise@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" + integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== + vite-tsconfig-paths@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.1.tgz#e53b89096b91d31a6d1e26f75999ea8c336a89ed" @@ -3419,6 +5633,42 @@ void-elements@3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +web-streams-polyfill@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + +webcrypto-core@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.7.tgz#06f24b3498463e570fed64d7cab149e5437b162c" + integrity sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g== + dependencies: + "@peculiar/asn1-schema" "^2.3.6" + "@peculiar/json-schema" "^1.1.12" + asn1js "^3.0.1" + pvtsutils "^1.3.2" + tslib "^2.4.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -3458,6 +5708,11 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + which-typed-array@^1.1.11, which-typed-array@^1.1.9: version "1.1.11" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" @@ -3476,6 +5731,15 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -3490,27 +5754,77 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@8.14.1, ws@^8.12.0, ws@^8.13.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.1.tgz#4b9586b4f70f9e6534c7bb1d3dc0baa8b8cf01e0" + integrity sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml-ast-parser@^0.0.43: + version "0.0.43" + resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb" + integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" + integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.7.2: +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^17.0.0, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 10a57d3388660d479773bdd2d007e923a986d916 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:10:14 +0200 Subject: [PATCH 04/47] Change "moduleResolution" to "node" "bundler" causes a tsc issue with the generated graphql file where the imported file can't be found. --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index d3a3900c..333123b0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,7 @@ /* Bundler mode */ "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "moduleResolution": "bundler", + "moduleResolution": "node", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, From 0087d3a87b13fffd9ad50e8d66fa98f38ade38d9 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:13:28 +0200 Subject: [PATCH 05/47] [Tool][Codegen] Add script to post format the generated graphql file Makes it possible to modify the generated graphql file by codegen. --- package.json | 4 +++- tools/scripts/codegenFormatter.ts | 33 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tools/scripts/codegenFormatter.ts diff --git a/package.json b/package.json index db611967..050cf70d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "lint": "eslint src --ext .ts,.tsx,.js,.jsx", "createChangelog": "ts-node tools/scripts/createReleaseChanglog.ts", "updateDeps": "yarn outdated && yarn upgrade && yarn syncyarnlock -s -k && yarn && git add package.json yarn.lock && git commit -m \"Update dependencies\"", - "gql:codegen": "graphql-codegen --config gql_codegen.ts" + "gql:codegen-base": "graphql-codegen --config gql_codegen.ts", + "gql:codegen-formatter": "ts-node tools/scripts/codegenFormatter.ts", + "gql:codegen": "yarn gql:codegen-base & yarn gql:codegen-formatter" }, "browserslist": { "production": [ diff --git a/tools/scripts/codegenFormatter.ts b/tools/scripts/codegenFormatter.ts new file mode 100644 index 00000000..8f7722e7 --- /dev/null +++ b/tools/scripts/codegenFormatter.ts @@ -0,0 +1,33 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import fs from 'fs'; +import * as path from 'path'; + +const format = (source: string, regex: RegExp, replaceValue: string): string => source.replace(regex, replaceValue); + +const generatedGraphQLFilePath = path.resolve(__dirname, '../../src/lib/graphql/generated/graphql.ts'); +const generatedGraphQLFile = fs.readFileSync(generatedGraphQLFilePath, 'utf8'); + +// add logic to format the codegen generated graphql file + +const fixCursorTyping = format( + generatedGraphQLFile, + /Cursor: \{ input: any; output: any; }/g, + 'Cursor: { input: string; output: string; }', +); + +const fixLongStringTyping = format( + fixCursorTyping, + /LongString: \{ input: any; output: any; }/g, + 'LongString: { input: string; output: string; }', +); + +const fixSubscriptionHookNameSuffix = format(fixLongStringTyping, /SubscriptionSubscription/g, 'Subscription'); + +fs.writeFileSync(generatedGraphQLFilePath, fixSubscriptionHookNameSuffix); From 87ddf2f8443140882f4e9d9334652ab6571c58ec Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 7 Aug 2023 23:32:36 +0200 Subject: [PATCH 06/47] [Codegen] Generate files Even if they are generated files, they should be checked-in so that it's possible to check out an old commit and still have the same files as they were at the time the commit was created. In case they wouldn't be checked-in and the schema has changed in the meantime, there is no possible way to build the same generated files anymore --- src/lib/graphql/generated/apollo-helpers.ts | 1250 +++++++++ src/lib/graphql/generated/graphql.ts | 2605 +++++++++++++++++++ 2 files changed, 3855 insertions(+) create mode 100644 src/lib/graphql/generated/apollo-helpers.ts create mode 100644 src/lib/graphql/generated/graphql.ts diff --git a/src/lib/graphql/generated/apollo-helpers.ts b/src/lib/graphql/generated/apollo-helpers.ts new file mode 100644 index 00000000..537bd8a4 --- /dev/null +++ b/src/lib/graphql/generated/apollo-helpers.ts @@ -0,0 +1,1250 @@ +import { FieldPolicy, FieldReadFunction, TypePolicies, TypePolicy } from '@apollo/client/cache'; +export type AboutPayloadKeySpecifier = ('buildTime' | 'buildType' | 'discord' | 'github' | 'name' | 'revision' | 'version' | AboutPayloadKeySpecifier)[]; +export type AboutPayloadFieldPolicy = { + buildTime?: FieldPolicy | FieldReadFunction, + buildType?: FieldPolicy | FieldReadFunction, + discord?: FieldPolicy | FieldReadFunction, + github?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + revision?: FieldPolicy | FieldReadFunction, + version?: FieldPolicy | FieldReadFunction +}; +export type BackupRestoreStatusKeySpecifier = ('mangaProgress' | 'state' | 'totalManga' | BackupRestoreStatusKeySpecifier)[]; +export type BackupRestoreStatusFieldPolicy = { + mangaProgress?: FieldPolicy | FieldReadFunction, + state?: FieldPolicy | FieldReadFunction, + totalManga?: FieldPolicy | FieldReadFunction +}; +export type CategoryEdgeKeySpecifier = ('cursor' | 'node' | CategoryEdgeKeySpecifier)[]; +export type CategoryEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type CategoryMetaTypeKeySpecifier = ('category' | 'categoryId' | 'key' | 'value' | CategoryMetaTypeKeySpecifier)[]; +export type CategoryMetaTypeFieldPolicy = { + category?: FieldPolicy | FieldReadFunction, + categoryId?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + value?: FieldPolicy | FieldReadFunction +}; +export type CategoryNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | CategoryNodeListKeySpecifier)[]; +export type CategoryNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type CategoryTypeKeySpecifier = ('default' | 'id' | 'includeInUpdate' | 'mangas' | 'meta' | 'name' | 'order' | CategoryTypeKeySpecifier)[]; +export type CategoryTypeFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + id?: FieldPolicy | FieldReadFunction, + includeInUpdate?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + order?: FieldPolicy | FieldReadFunction +}; +export type ChapterEdgeKeySpecifier = ('cursor' | 'node' | ChapterEdgeKeySpecifier)[]; +export type ChapterEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type ChapterMetaTypeKeySpecifier = ('chapter' | 'chapterId' | 'key' | 'value' | ChapterMetaTypeKeySpecifier)[]; +export type ChapterMetaTypeFieldPolicy = { + chapter?: FieldPolicy | FieldReadFunction, + chapterId?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + value?: FieldPolicy | FieldReadFunction +}; +export type ChapterNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | ChapterNodeListKeySpecifier)[]; +export type ChapterNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type ChapterTypeKeySpecifier = ('chapterNumber' | 'fetchedAt' | 'id' | 'isBookmarked' | 'isDownloaded' | 'isRead' | 'lastPageRead' | 'lastReadAt' | 'manga' | 'mangaId' | 'meta' | 'name' | 'pageCount' | 'realUrl' | 'scanlator' | 'sourceOrder' | 'uploadDate' | 'url' | ChapterTypeKeySpecifier)[]; +export type ChapterTypeFieldPolicy = { + chapterNumber?: FieldPolicy | FieldReadFunction, + fetchedAt?: FieldPolicy | FieldReadFunction, + id?: FieldPolicy | FieldReadFunction, + isBookmarked?: FieldPolicy | FieldReadFunction, + isDownloaded?: FieldPolicy | FieldReadFunction, + isRead?: FieldPolicy | FieldReadFunction, + lastPageRead?: FieldPolicy | FieldReadFunction, + lastReadAt?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + mangaId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + pageCount?: FieldPolicy | FieldReadFunction, + realUrl?: FieldPolicy | FieldReadFunction, + scanlator?: FieldPolicy | FieldReadFunction, + sourceOrder?: FieldPolicy | FieldReadFunction, + uploadDate?: FieldPolicy | FieldReadFunction, + url?: FieldPolicy | FieldReadFunction +}; +export type CheckBoxFilterKeySpecifier = ('default' | 'name' | CheckBoxFilterKeySpecifier)[]; +export type CheckBoxFilterFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction +}; +export type CheckBoxPreferenceKeySpecifier = ('currentValue' | 'default' | 'key' | 'summary' | 'title' | 'visible' | CheckBoxPreferenceKeySpecifier)[]; +export type CheckBoxPreferenceFieldPolicy = { + currentValue?: FieldPolicy | FieldReadFunction, + default?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + summary?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + visible?: FieldPolicy | FieldReadFunction +}; +export type CheckForServerUpdatesPayloadKeySpecifier = ('channel' | 'tag' | 'url' | CheckForServerUpdatesPayloadKeySpecifier)[]; +export type CheckForServerUpdatesPayloadFieldPolicy = { + channel?: FieldPolicy | FieldReadFunction, + tag?: FieldPolicy | FieldReadFunction, + url?: FieldPolicy | FieldReadFunction +}; +export type ClearDownloaderPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | ClearDownloaderPayloadKeySpecifier)[]; +export type ClearDownloaderPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type CreateBackupPayloadKeySpecifier = ('clientMutationId' | 'url' | CreateBackupPayloadKeySpecifier)[]; +export type CreateBackupPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + url?: FieldPolicy | FieldReadFunction +}; +export type CreateCategoryPayloadKeySpecifier = ('category' | 'clientMutationId' | CreateCategoryPayloadKeySpecifier)[]; +export type CreateCategoryPayloadFieldPolicy = { + category?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type DeleteCategoryMetaPayloadKeySpecifier = ('category' | 'clientMutationId' | 'meta' | DeleteCategoryMetaPayloadKeySpecifier)[]; +export type DeleteCategoryMetaPayloadFieldPolicy = { + category?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type DeleteCategoryPayloadKeySpecifier = ('category' | 'clientMutationId' | 'mangas' | DeleteCategoryPayloadKeySpecifier)[]; +export type DeleteCategoryPayloadFieldPolicy = { + category?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction +}; +export type DeleteChapterMetaPayloadKeySpecifier = ('chapter' | 'clientMutationId' | 'meta' | DeleteChapterMetaPayloadKeySpecifier)[]; +export type DeleteChapterMetaPayloadFieldPolicy = { + chapter?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type DeleteDownloadedChapterPayloadKeySpecifier = ('chapters' | 'clientMutationId' | DeleteDownloadedChapterPayloadKeySpecifier)[]; +export type DeleteDownloadedChapterPayloadFieldPolicy = { + chapters?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type DeleteDownloadedChaptersPayloadKeySpecifier = ('chapters' | 'clientMutationId' | DeleteDownloadedChaptersPayloadKeySpecifier)[]; +export type DeleteDownloadedChaptersPayloadFieldPolicy = { + chapters?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type DeleteGlobalMetaPayloadKeySpecifier = ('clientMutationId' | 'meta' | DeleteGlobalMetaPayloadKeySpecifier)[]; +export type DeleteGlobalMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type DeleteMangaMetaPayloadKeySpecifier = ('clientMutationId' | 'manga' | 'meta' | DeleteMangaMetaPayloadKeySpecifier)[]; +export type DeleteMangaMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type DequeueChapterDownloadPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | DequeueChapterDownloadPayloadKeySpecifier)[]; +export type DequeueChapterDownloadPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type DequeueChapterDownloadsPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | DequeueChapterDownloadsPayloadKeySpecifier)[]; +export type DequeueChapterDownloadsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type DownloadAheadPayloadKeySpecifier = ('clientMutationId' | DownloadAheadPayloadKeySpecifier)[]; +export type DownloadAheadPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type DownloadEdgeKeySpecifier = ('cursor' | 'node' | DownloadEdgeKeySpecifier)[]; +export type DownloadEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type DownloadNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | DownloadNodeListKeySpecifier)[]; +export type DownloadNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type DownloadStatusKeySpecifier = ('queue' | 'state' | DownloadStatusKeySpecifier)[]; +export type DownloadStatusFieldPolicy = { + queue?: FieldPolicy | FieldReadFunction, + state?: FieldPolicy | FieldReadFunction +}; +export type DownloadTypeKeySpecifier = ('chapter' | 'manga' | 'progress' | 'state' | 'tries' | DownloadTypeKeySpecifier)[]; +export type DownloadTypeFieldPolicy = { + chapter?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + progress?: FieldPolicy | FieldReadFunction, + state?: FieldPolicy | FieldReadFunction, + tries?: FieldPolicy | FieldReadFunction +}; +export type EdgeKeySpecifier = ('cursor' | 'node' | EdgeKeySpecifier)[]; +export type EdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type EditTextPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'key' | 'summary' | 'text' | 'title' | 'visible' | EditTextPreferenceKeySpecifier)[]; +export type EditTextPreferenceFieldPolicy = { + currentValue?: FieldPolicy | FieldReadFunction, + default?: FieldPolicy | FieldReadFunction, + dialogMessage?: FieldPolicy | FieldReadFunction, + dialogTitle?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + summary?: FieldPolicy | FieldReadFunction, + text?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + visible?: FieldPolicy | FieldReadFunction +}; +export type EnqueueChapterDownloadPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | EnqueueChapterDownloadPayloadKeySpecifier)[]; +export type EnqueueChapterDownloadPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type EnqueueChapterDownloadsPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | EnqueueChapterDownloadsPayloadKeySpecifier)[]; +export type EnqueueChapterDownloadsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type ExtensionEdgeKeySpecifier = ('cursor' | 'node' | ExtensionEdgeKeySpecifier)[]; +export type ExtensionEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type ExtensionNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | ExtensionNodeListKeySpecifier)[]; +export type ExtensionNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type ExtensionTypeKeySpecifier = ('apkName' | 'hasUpdate' | 'iconUrl' | 'isInstalled' | 'isNsfw' | 'isObsolete' | 'lang' | 'name' | 'pkgName' | 'source' | 'versionCode' | 'versionName' | ExtensionTypeKeySpecifier)[]; +export type ExtensionTypeFieldPolicy = { + apkName?: FieldPolicy | FieldReadFunction, + hasUpdate?: FieldPolicy | FieldReadFunction, + iconUrl?: FieldPolicy | FieldReadFunction, + isInstalled?: FieldPolicy | FieldReadFunction, + isNsfw?: FieldPolicy | FieldReadFunction, + isObsolete?: FieldPolicy | FieldReadFunction, + lang?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + pkgName?: FieldPolicy | FieldReadFunction, + source?: FieldPolicy | FieldReadFunction, + versionCode?: FieldPolicy | FieldReadFunction, + versionName?: FieldPolicy | FieldReadFunction +}; +export type FetchChapterPagesPayloadKeySpecifier = ('chapter' | 'clientMutationId' | 'pages' | FetchChapterPagesPayloadKeySpecifier)[]; +export type FetchChapterPagesPayloadFieldPolicy = { + chapter?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction, + pages?: FieldPolicy | FieldReadFunction +}; +export type FetchChaptersPayloadKeySpecifier = ('chapters' | 'clientMutationId' | FetchChaptersPayloadKeySpecifier)[]; +export type FetchChaptersPayloadFieldPolicy = { + chapters?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type FetchExtensionsPayloadKeySpecifier = ('clientMutationId' | 'extensions' | FetchExtensionsPayloadKeySpecifier)[]; +export type FetchExtensionsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + extensions?: FieldPolicy | FieldReadFunction +}; +export type FetchMangaPayloadKeySpecifier = ('clientMutationId' | 'manga' | FetchMangaPayloadKeySpecifier)[]; +export type FetchMangaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction +}; +export type FetchSourceMangaPayloadKeySpecifier = ('clientMutationId' | 'hasNextPage' | 'mangas' | FetchSourceMangaPayloadKeySpecifier)[]; +export type FetchSourceMangaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + hasNextPage?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction +}; +export type GlobalMetaNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | GlobalMetaNodeListKeySpecifier)[]; +export type GlobalMetaNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type GlobalMetaTypeKeySpecifier = ('key' | 'value' | GlobalMetaTypeKeySpecifier)[]; +export type GlobalMetaTypeFieldPolicy = { + key?: FieldPolicy | FieldReadFunction, + value?: FieldPolicy | FieldReadFunction +}; +export type GroupFilterKeySpecifier = ('filters' | 'name' | GroupFilterKeySpecifier)[]; +export type GroupFilterFieldPolicy = { + filters?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction +}; +export type HeaderFilterKeySpecifier = ('name' | HeaderFilterKeySpecifier)[]; +export type HeaderFilterFieldPolicy = { + name?: FieldPolicy | FieldReadFunction +}; +export type InstallExternalExtensionPayloadKeySpecifier = ('clientMutationId' | 'extension' | InstallExternalExtensionPayloadKeySpecifier)[]; +export type InstallExternalExtensionPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + extension?: FieldPolicy | FieldReadFunction +}; +export type LastUpdateTimestampPayloadKeySpecifier = ('timestamp' | LastUpdateTimestampPayloadKeySpecifier)[]; +export type LastUpdateTimestampPayloadFieldPolicy = { + timestamp?: FieldPolicy | FieldReadFunction +}; +export type ListPreferenceKeySpecifier = ('currentValue' | 'default' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | ListPreferenceKeySpecifier)[]; +export type ListPreferenceFieldPolicy = { + currentValue?: FieldPolicy | FieldReadFunction, + default?: FieldPolicy | FieldReadFunction, + entries?: FieldPolicy | FieldReadFunction, + entryValues?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + summary?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + visible?: FieldPolicy | FieldReadFunction +}; +export type MangaEdgeKeySpecifier = ('cursor' | 'node' | MangaEdgeKeySpecifier)[]; +export type MangaEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type MangaMetaTypeKeySpecifier = ('key' | 'manga' | 'mangaId' | 'value' | MangaMetaTypeKeySpecifier)[]; +export type MangaMetaTypeFieldPolicy = { + key?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + mangaId?: FieldPolicy | FieldReadFunction, + value?: FieldPolicy | FieldReadFunction +}; +export type MangaNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | MangaNodeListKeySpecifier)[]; +export type MangaNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type MangaTypeKeySpecifier = ('age' | 'artist' | 'author' | 'categories' | 'chapters' | 'chaptersAge' | 'chaptersLastFetchedAt' | 'description' | 'downloadCount' | 'genre' | 'id' | 'inLibrary' | 'inLibraryAt' | 'initialized' | 'lastFetchedAt' | 'lastReadChapter' | 'meta' | 'realUrl' | 'source' | 'sourceId' | 'status' | 'thumbnailUrl' | 'title' | 'unreadCount' | 'url' | MangaTypeKeySpecifier)[]; +export type MangaTypeFieldPolicy = { + age?: FieldPolicy | FieldReadFunction, + artist?: FieldPolicy | FieldReadFunction, + author?: FieldPolicy | FieldReadFunction, + categories?: FieldPolicy | FieldReadFunction, + chapters?: FieldPolicy | FieldReadFunction, + chaptersAge?: FieldPolicy | FieldReadFunction, + chaptersLastFetchedAt?: FieldPolicy | FieldReadFunction, + description?: FieldPolicy | FieldReadFunction, + downloadCount?: FieldPolicy | FieldReadFunction, + genre?: FieldPolicy | FieldReadFunction, + id?: FieldPolicy | FieldReadFunction, + inLibrary?: FieldPolicy | FieldReadFunction, + inLibraryAt?: FieldPolicy | FieldReadFunction, + initialized?: FieldPolicy | FieldReadFunction, + lastFetchedAt?: FieldPolicy | FieldReadFunction, + lastReadChapter?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction, + realUrl?: FieldPolicy | FieldReadFunction, + source?: FieldPolicy | FieldReadFunction, + sourceId?: FieldPolicy | FieldReadFunction, + status?: FieldPolicy | FieldReadFunction, + thumbnailUrl?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + unreadCount?: FieldPolicy | FieldReadFunction, + url?: FieldPolicy | FieldReadFunction +}; +export type MetaEdgeKeySpecifier = ('cursor' | 'node' | MetaEdgeKeySpecifier)[]; +export type MetaEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type MetaTypeKeySpecifier = ('key' | 'value' | MetaTypeKeySpecifier)[]; +export type MetaTypeFieldPolicy = { + key?: FieldPolicy | FieldReadFunction, + value?: FieldPolicy | FieldReadFunction +}; +export type MultiSelectListPreferenceKeySpecifier = ('currentValue' | 'default' | 'dialogMessage' | 'dialogTitle' | 'entries' | 'entryValues' | 'key' | 'summary' | 'title' | 'visible' | MultiSelectListPreferenceKeySpecifier)[]; +export type MultiSelectListPreferenceFieldPolicy = { + currentValue?: FieldPolicy | FieldReadFunction, + default?: FieldPolicy | FieldReadFunction, + dialogMessage?: FieldPolicy | FieldReadFunction, + dialogTitle?: FieldPolicy | FieldReadFunction, + entries?: FieldPolicy | FieldReadFunction, + entryValues?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + summary?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + visible?: FieldPolicy | FieldReadFunction +}; +export type MutationKeySpecifier = ('clearDownloader' | 'createBackup' | 'createCategory' | 'deleteCategory' | 'deleteCategoryMeta' | 'deleteChapterMeta' | 'deleteDownloadedChapter' | 'deleteDownloadedChapters' | 'deleteGlobalMeta' | 'deleteMangaMeta' | 'dequeueChapterDownload' | 'dequeueChapterDownloads' | 'downloadAhead' | 'enqueueChapterDownload' | 'enqueueChapterDownloads' | 'fetchChapterPages' | 'fetchChapters' | 'fetchExtensions' | 'fetchManga' | 'fetchSourceManga' | 'installExternalExtension' | 'reorderChapterDownload' | 'resetSettings' | 'restoreBackup' | 'setCategoryMeta' | 'setChapterMeta' | 'setGlobalMeta' | 'setMangaMeta' | 'setSettings' | 'startDownloader' | 'stopDownloader' | 'updateCategories' | 'updateCategory' | 'updateCategoryManga' | 'updateCategoryOrder' | 'updateChapter' | 'updateChapters' | 'updateExtension' | 'updateExtensions' | 'updateLibraryManga' | 'updateManga' | 'updateMangaCategories' | 'updateMangas' | 'updateMangasCategories' | 'updateSourcePreference' | 'updateStop' | 'updateWebUI' | MutationKeySpecifier)[]; +export type MutationFieldPolicy = { + clearDownloader?: FieldPolicy | FieldReadFunction, + createBackup?: FieldPolicy | FieldReadFunction, + createCategory?: FieldPolicy | FieldReadFunction, + deleteCategory?: FieldPolicy | FieldReadFunction, + deleteCategoryMeta?: FieldPolicy | FieldReadFunction, + deleteChapterMeta?: FieldPolicy | FieldReadFunction, + deleteDownloadedChapter?: FieldPolicy | FieldReadFunction, + deleteDownloadedChapters?: FieldPolicy | FieldReadFunction, + deleteGlobalMeta?: FieldPolicy | FieldReadFunction, + deleteMangaMeta?: FieldPolicy | FieldReadFunction, + dequeueChapterDownload?: FieldPolicy | FieldReadFunction, + dequeueChapterDownloads?: FieldPolicy | FieldReadFunction, + downloadAhead?: FieldPolicy | FieldReadFunction, + enqueueChapterDownload?: FieldPolicy | FieldReadFunction, + enqueueChapterDownloads?: FieldPolicy | FieldReadFunction, + fetchChapterPages?: FieldPolicy | FieldReadFunction, + fetchChapters?: FieldPolicy | FieldReadFunction, + fetchExtensions?: FieldPolicy | FieldReadFunction, + fetchManga?: FieldPolicy | FieldReadFunction, + fetchSourceManga?: FieldPolicy | FieldReadFunction, + installExternalExtension?: FieldPolicy | FieldReadFunction, + reorderChapterDownload?: FieldPolicy | FieldReadFunction, + resetSettings?: FieldPolicy | FieldReadFunction, + restoreBackup?: FieldPolicy | FieldReadFunction, + setCategoryMeta?: FieldPolicy | FieldReadFunction, + setChapterMeta?: FieldPolicy | FieldReadFunction, + setGlobalMeta?: FieldPolicy | FieldReadFunction, + setMangaMeta?: FieldPolicy | FieldReadFunction, + setSettings?: FieldPolicy | FieldReadFunction, + startDownloader?: FieldPolicy | FieldReadFunction, + stopDownloader?: FieldPolicy | FieldReadFunction, + updateCategories?: FieldPolicy | FieldReadFunction, + updateCategory?: FieldPolicy | FieldReadFunction, + updateCategoryManga?: FieldPolicy | FieldReadFunction, + updateCategoryOrder?: FieldPolicy | FieldReadFunction, + updateChapter?: FieldPolicy | FieldReadFunction, + updateChapters?: FieldPolicy | FieldReadFunction, + updateExtension?: FieldPolicy | FieldReadFunction, + updateExtensions?: FieldPolicy | FieldReadFunction, + updateLibraryManga?: FieldPolicy | FieldReadFunction, + updateManga?: FieldPolicy | FieldReadFunction, + updateMangaCategories?: FieldPolicy | FieldReadFunction, + updateMangas?: FieldPolicy | FieldReadFunction, + updateMangasCategories?: FieldPolicy | FieldReadFunction, + updateSourcePreference?: FieldPolicy | FieldReadFunction, + updateStop?: FieldPolicy | FieldReadFunction, + updateWebUI?: FieldPolicy | FieldReadFunction +}; +export type NodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | NodeListKeySpecifier)[]; +export type NodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type PageInfoKeySpecifier = ('endCursor' | 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | PageInfoKeySpecifier)[]; +export type PageInfoFieldPolicy = { + endCursor?: FieldPolicy | FieldReadFunction, + hasNextPage?: FieldPolicy | FieldReadFunction, + hasPreviousPage?: FieldPolicy | FieldReadFunction, + startCursor?: FieldPolicy | FieldReadFunction +}; +export type PartialSettingsTypeKeySpecifier = ('autoDownloadNewChapters' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'globalUpdateInterval' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxSourcesInParallel' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPort' | 'systemTrayEnabled' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | PartialSettingsTypeKeySpecifier)[]; +export type PartialSettingsTypeFieldPolicy = { + autoDownloadNewChapters?: FieldPolicy | FieldReadFunction, + backupInterval?: FieldPolicy | FieldReadFunction, + backupPath?: FieldPolicy | FieldReadFunction, + backupTTL?: FieldPolicy | FieldReadFunction, + backupTime?: FieldPolicy | FieldReadFunction, + basicAuthEnabled?: FieldPolicy | FieldReadFunction, + basicAuthPassword?: FieldPolicy | FieldReadFunction, + basicAuthUsername?: FieldPolicy | FieldReadFunction, + debugLogsEnabled?: FieldPolicy | FieldReadFunction, + downloadAsCbz?: FieldPolicy | FieldReadFunction, + downloadsPath?: FieldPolicy | FieldReadFunction, + electronPath?: FieldPolicy | FieldReadFunction, + excludeCompleted?: FieldPolicy | FieldReadFunction, + excludeNotStarted?: FieldPolicy | FieldReadFunction, + excludeUnreadChapters?: FieldPolicy | FieldReadFunction, + globalUpdateInterval?: FieldPolicy | FieldReadFunction, + initialOpenInBrowserEnabled?: FieldPolicy | FieldReadFunction, + ip?: FieldPolicy | FieldReadFunction, + localSourcePath?: FieldPolicy | FieldReadFunction, + maxSourcesInParallel?: FieldPolicy | FieldReadFunction, + port?: FieldPolicy | FieldReadFunction, + socksProxyEnabled?: FieldPolicy | FieldReadFunction, + socksProxyHost?: FieldPolicy | FieldReadFunction, + socksProxyPort?: FieldPolicy | FieldReadFunction, + systemTrayEnabled?: FieldPolicy | FieldReadFunction, + webUIChannel?: FieldPolicy | FieldReadFunction, + webUIFlavor?: FieldPolicy | FieldReadFunction, + webUIInterface?: FieldPolicy | FieldReadFunction, + webUIUpdateCheckInterval?: FieldPolicy | FieldReadFunction +}; +export type QueryKeySpecifier = ('about' | 'categories' | 'category' | 'chapter' | 'chapters' | 'checkForServerUpdates' | 'checkForWebUIUpdate' | 'downloadStatus' | 'extension' | 'extensions' | 'getWebUIUpdateStatus' | 'lastUpdateTimestamp' | 'manga' | 'mangas' | 'meta' | 'metas' | 'restoreStatus' | 'settings' | 'source' | 'sources' | 'updateStatus' | 'validateBackup' | QueryKeySpecifier)[]; +export type QueryFieldPolicy = { + about?: FieldPolicy | FieldReadFunction, + categories?: FieldPolicy | FieldReadFunction, + category?: FieldPolicy | FieldReadFunction, + chapter?: FieldPolicy | FieldReadFunction, + chapters?: FieldPolicy | FieldReadFunction, + checkForServerUpdates?: FieldPolicy | FieldReadFunction, + checkForWebUIUpdate?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction, + extension?: FieldPolicy | FieldReadFunction, + extensions?: FieldPolicy | FieldReadFunction, + getWebUIUpdateStatus?: FieldPolicy | FieldReadFunction, + lastUpdateTimestamp?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction, + metas?: FieldPolicy | FieldReadFunction, + restoreStatus?: FieldPolicy | FieldReadFunction, + settings?: FieldPolicy | FieldReadFunction, + source?: FieldPolicy | FieldReadFunction, + sources?: FieldPolicy | FieldReadFunction, + updateStatus?: FieldPolicy | FieldReadFunction, + validateBackup?: FieldPolicy | FieldReadFunction +}; +export type ReorderChapterDownloadPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | ReorderChapterDownloadPayloadKeySpecifier)[]; +export type ReorderChapterDownloadPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type ResetSettingsPayloadKeySpecifier = ('clientMutationId' | 'settings' | ResetSettingsPayloadKeySpecifier)[]; +export type ResetSettingsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + settings?: FieldPolicy | FieldReadFunction +}; +export type RestoreBackupPayloadKeySpecifier = ('clientMutationId' | 'status' | RestoreBackupPayloadKeySpecifier)[]; +export type RestoreBackupPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + status?: FieldPolicy | FieldReadFunction +}; +export type SelectFilterKeySpecifier = ('default' | 'name' | 'values' | SelectFilterKeySpecifier)[]; +export type SelectFilterFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + values?: FieldPolicy | FieldReadFunction +}; +export type SeparatorFilterKeySpecifier = ('name' | SeparatorFilterKeySpecifier)[]; +export type SeparatorFilterFieldPolicy = { + name?: FieldPolicy | FieldReadFunction +}; +export type SetCategoryMetaPayloadKeySpecifier = ('clientMutationId' | 'meta' | SetCategoryMetaPayloadKeySpecifier)[]; +export type SetCategoryMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type SetChapterMetaPayloadKeySpecifier = ('clientMutationId' | 'meta' | SetChapterMetaPayloadKeySpecifier)[]; +export type SetChapterMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type SetGlobalMetaPayloadKeySpecifier = ('clientMutationId' | 'meta' | SetGlobalMetaPayloadKeySpecifier)[]; +export type SetGlobalMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type SetMangaMetaPayloadKeySpecifier = ('clientMutationId' | 'meta' | SetMangaMetaPayloadKeySpecifier)[]; +export type SetMangaMetaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + meta?: FieldPolicy | FieldReadFunction +}; +export type SetSettingsPayloadKeySpecifier = ('clientMutationId' | 'settings' | SetSettingsPayloadKeySpecifier)[]; +export type SetSettingsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + settings?: FieldPolicy | FieldReadFunction +}; +export type SettingsKeySpecifier = ('autoDownloadNewChapters' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'globalUpdateInterval' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxSourcesInParallel' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPort' | 'systemTrayEnabled' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsKeySpecifier)[]; +export type SettingsFieldPolicy = { + autoDownloadNewChapters?: FieldPolicy | FieldReadFunction, + backupInterval?: FieldPolicy | FieldReadFunction, + backupPath?: FieldPolicy | FieldReadFunction, + backupTTL?: FieldPolicy | FieldReadFunction, + backupTime?: FieldPolicy | FieldReadFunction, + basicAuthEnabled?: FieldPolicy | FieldReadFunction, + basicAuthPassword?: FieldPolicy | FieldReadFunction, + basicAuthUsername?: FieldPolicy | FieldReadFunction, + debugLogsEnabled?: FieldPolicy | FieldReadFunction, + downloadAsCbz?: FieldPolicy | FieldReadFunction, + downloadsPath?: FieldPolicy | FieldReadFunction, + electronPath?: FieldPolicy | FieldReadFunction, + excludeCompleted?: FieldPolicy | FieldReadFunction, + excludeNotStarted?: FieldPolicy | FieldReadFunction, + excludeUnreadChapters?: FieldPolicy | FieldReadFunction, + globalUpdateInterval?: FieldPolicy | FieldReadFunction, + initialOpenInBrowserEnabled?: FieldPolicy | FieldReadFunction, + ip?: FieldPolicy | FieldReadFunction, + localSourcePath?: FieldPolicy | FieldReadFunction, + maxSourcesInParallel?: FieldPolicy | FieldReadFunction, + port?: FieldPolicy | FieldReadFunction, + socksProxyEnabled?: FieldPolicy | FieldReadFunction, + socksProxyHost?: FieldPolicy | FieldReadFunction, + socksProxyPort?: FieldPolicy | FieldReadFunction, + systemTrayEnabled?: FieldPolicy | FieldReadFunction, + webUIChannel?: FieldPolicy | FieldReadFunction, + webUIFlavor?: FieldPolicy | FieldReadFunction, + webUIInterface?: FieldPolicy | FieldReadFunction, + webUIUpdateCheckInterval?: FieldPolicy | FieldReadFunction +}; +export type SettingsTypeKeySpecifier = ('autoDownloadNewChapters' | 'backupInterval' | 'backupPath' | 'backupTTL' | 'backupTime' | 'basicAuthEnabled' | 'basicAuthPassword' | 'basicAuthUsername' | 'debugLogsEnabled' | 'downloadAsCbz' | 'downloadsPath' | 'electronPath' | 'excludeCompleted' | 'excludeNotStarted' | 'excludeUnreadChapters' | 'globalUpdateInterval' | 'initialOpenInBrowserEnabled' | 'ip' | 'localSourcePath' | 'maxSourcesInParallel' | 'port' | 'socksProxyEnabled' | 'socksProxyHost' | 'socksProxyPort' | 'systemTrayEnabled' | 'webUIChannel' | 'webUIFlavor' | 'webUIInterface' | 'webUIUpdateCheckInterval' | SettingsTypeKeySpecifier)[]; +export type SettingsTypeFieldPolicy = { + autoDownloadNewChapters?: FieldPolicy | FieldReadFunction, + backupInterval?: FieldPolicy | FieldReadFunction, + backupPath?: FieldPolicy | FieldReadFunction, + backupTTL?: FieldPolicy | FieldReadFunction, + backupTime?: FieldPolicy | FieldReadFunction, + basicAuthEnabled?: FieldPolicy | FieldReadFunction, + basicAuthPassword?: FieldPolicy | FieldReadFunction, + basicAuthUsername?: FieldPolicy | FieldReadFunction, + debugLogsEnabled?: FieldPolicy | FieldReadFunction, + downloadAsCbz?: FieldPolicy | FieldReadFunction, + downloadsPath?: FieldPolicy | FieldReadFunction, + electronPath?: FieldPolicy | FieldReadFunction, + excludeCompleted?: FieldPolicy | FieldReadFunction, + excludeNotStarted?: FieldPolicy | FieldReadFunction, + excludeUnreadChapters?: FieldPolicy | FieldReadFunction, + globalUpdateInterval?: FieldPolicy | FieldReadFunction, + initialOpenInBrowserEnabled?: FieldPolicy | FieldReadFunction, + ip?: FieldPolicy | FieldReadFunction, + localSourcePath?: FieldPolicy | FieldReadFunction, + maxSourcesInParallel?: FieldPolicy | FieldReadFunction, + port?: FieldPolicy | FieldReadFunction, + socksProxyEnabled?: FieldPolicy | FieldReadFunction, + socksProxyHost?: FieldPolicy | FieldReadFunction, + socksProxyPort?: FieldPolicy | FieldReadFunction, + systemTrayEnabled?: FieldPolicy | FieldReadFunction, + webUIChannel?: FieldPolicy | FieldReadFunction, + webUIFlavor?: FieldPolicy | FieldReadFunction, + webUIInterface?: FieldPolicy | FieldReadFunction, + webUIUpdateCheckInterval?: FieldPolicy | FieldReadFunction +}; +export type SortFilterKeySpecifier = ('default' | 'name' | 'values' | SortFilterKeySpecifier)[]; +export type SortFilterFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + values?: FieldPolicy | FieldReadFunction +}; +export type SortSelectionKeySpecifier = ('ascending' | 'index' | SortSelectionKeySpecifier)[]; +export type SortSelectionFieldPolicy = { + ascending?: FieldPolicy | FieldReadFunction, + index?: FieldPolicy | FieldReadFunction +}; +export type SourceEdgeKeySpecifier = ('cursor' | 'node' | SourceEdgeKeySpecifier)[]; +export type SourceEdgeFieldPolicy = { + cursor?: FieldPolicy | FieldReadFunction, + node?: FieldPolicy | FieldReadFunction +}; +export type SourceNodeListKeySpecifier = ('edges' | 'nodes' | 'pageInfo' | 'totalCount' | SourceNodeListKeySpecifier)[]; +export type SourceNodeListFieldPolicy = { + edges?: FieldPolicy | FieldReadFunction, + nodes?: FieldPolicy | FieldReadFunction, + pageInfo?: FieldPolicy | FieldReadFunction, + totalCount?: FieldPolicy | FieldReadFunction +}; +export type SourceTypeKeySpecifier = ('displayName' | 'extension' | 'filters' | 'iconUrl' | 'id' | 'isConfigurable' | 'isNsfw' | 'lang' | 'manga' | 'name' | 'preferences' | 'supportsLatest' | SourceTypeKeySpecifier)[]; +export type SourceTypeFieldPolicy = { + displayName?: FieldPolicy | FieldReadFunction, + extension?: FieldPolicy | FieldReadFunction, + filters?: FieldPolicy | FieldReadFunction, + iconUrl?: FieldPolicy | FieldReadFunction, + id?: FieldPolicy | FieldReadFunction, + isConfigurable?: FieldPolicy | FieldReadFunction, + isNsfw?: FieldPolicy | FieldReadFunction, + lang?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction, + preferences?: FieldPolicy | FieldReadFunction, + supportsLatest?: FieldPolicy | FieldReadFunction +}; +export type StartDownloaderPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | StartDownloaderPayloadKeySpecifier)[]; +export type StartDownloaderPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type StopDownloaderPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | StopDownloaderPayloadKeySpecifier)[]; +export type StopDownloaderPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + downloadStatus?: FieldPolicy | FieldReadFunction +}; +export type SubscriptionKeySpecifier = ('downloadChanged' | 'updateStatusChanged' | 'webUIUpdateStatusChange' | SubscriptionKeySpecifier)[]; +export type SubscriptionFieldPolicy = { + downloadChanged?: FieldPolicy | FieldReadFunction, + updateStatusChanged?: FieldPolicy | FieldReadFunction, + webUIUpdateStatusChange?: FieldPolicy | FieldReadFunction +}; +export type SwitchPreferenceKeySpecifier = ('currentValue' | 'default' | 'key' | 'summary' | 'title' | 'visible' | SwitchPreferenceKeySpecifier)[]; +export type SwitchPreferenceFieldPolicy = { + currentValue?: FieldPolicy | FieldReadFunction, + default?: FieldPolicy | FieldReadFunction, + key?: FieldPolicy | FieldReadFunction, + summary?: FieldPolicy | FieldReadFunction, + title?: FieldPolicy | FieldReadFunction, + visible?: FieldPolicy | FieldReadFunction +}; +export type TextFilterKeySpecifier = ('default' | 'name' | TextFilterKeySpecifier)[]; +export type TextFilterFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction +}; +export type TriStateFilterKeySpecifier = ('default' | 'name' | TriStateFilterKeySpecifier)[]; +export type TriStateFilterFieldPolicy = { + default?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction +}; +export type UpdateCategoriesPayloadKeySpecifier = ('categories' | 'clientMutationId' | UpdateCategoriesPayloadKeySpecifier)[]; +export type UpdateCategoriesPayloadFieldPolicy = { + categories?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type UpdateCategoryMangaPayloadKeySpecifier = ('clientMutationId' | 'updateStatus' | UpdateCategoryMangaPayloadKeySpecifier)[]; +export type UpdateCategoryMangaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + updateStatus?: FieldPolicy | FieldReadFunction +}; +export type UpdateCategoryOrderPayloadKeySpecifier = ('categories' | 'clientMutationId' | UpdateCategoryOrderPayloadKeySpecifier)[]; +export type UpdateCategoryOrderPayloadFieldPolicy = { + categories?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type UpdateCategoryPayloadKeySpecifier = ('category' | 'clientMutationId' | UpdateCategoryPayloadKeySpecifier)[]; +export type UpdateCategoryPayloadFieldPolicy = { + category?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type UpdateChapterPayloadKeySpecifier = ('chapter' | 'clientMutationId' | UpdateChapterPayloadKeySpecifier)[]; +export type UpdateChapterPayloadFieldPolicy = { + chapter?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type UpdateChaptersPayloadKeySpecifier = ('chapters' | 'clientMutationId' | UpdateChaptersPayloadKeySpecifier)[]; +export type UpdateChaptersPayloadFieldPolicy = { + chapters?: FieldPolicy | FieldReadFunction, + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type UpdateExtensionPayloadKeySpecifier = ('clientMutationId' | 'extension' | UpdateExtensionPayloadKeySpecifier)[]; +export type UpdateExtensionPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + extension?: FieldPolicy | FieldReadFunction +}; +export type UpdateExtensionsPayloadKeySpecifier = ('clientMutationId' | 'extensions' | UpdateExtensionsPayloadKeySpecifier)[]; +export type UpdateExtensionsPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + extensions?: FieldPolicy | FieldReadFunction +}; +export type UpdateLibraryMangaPayloadKeySpecifier = ('clientMutationId' | 'updateStatus' | UpdateLibraryMangaPayloadKeySpecifier)[]; +export type UpdateLibraryMangaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + updateStatus?: FieldPolicy | FieldReadFunction +}; +export type UpdateMangaCategoriesPayloadKeySpecifier = ('clientMutationId' | 'manga' | UpdateMangaCategoriesPayloadKeySpecifier)[]; +export type UpdateMangaCategoriesPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction +}; +export type UpdateMangaPayloadKeySpecifier = ('clientMutationId' | 'manga' | UpdateMangaPayloadKeySpecifier)[]; +export type UpdateMangaPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + manga?: FieldPolicy | FieldReadFunction +}; +export type UpdateMangasCategoriesPayloadKeySpecifier = ('clientMutationId' | 'mangas' | UpdateMangasCategoriesPayloadKeySpecifier)[]; +export type UpdateMangasCategoriesPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction +}; +export type UpdateMangasPayloadKeySpecifier = ('clientMutationId' | 'mangas' | UpdateMangasPayloadKeySpecifier)[]; +export type UpdateMangasPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + mangas?: FieldPolicy | FieldReadFunction +}; +export type UpdateSourcePreferencePayloadKeySpecifier = ('clientMutationId' | 'preferences' | 'source' | UpdateSourcePreferencePayloadKeySpecifier)[]; +export type UpdateSourcePreferencePayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + preferences?: FieldPolicy | FieldReadFunction, + source?: FieldPolicy | FieldReadFunction +}; +export type UpdateStatusKeySpecifier = ('completeJobs' | 'failedJobs' | 'isRunning' | 'pendingJobs' | 'runningJobs' | 'skippedCategories' | 'skippedJobs' | 'updatingCategories' | UpdateStatusKeySpecifier)[]; +export type UpdateStatusFieldPolicy = { + completeJobs?: FieldPolicy | FieldReadFunction, + failedJobs?: FieldPolicy | FieldReadFunction, + isRunning?: FieldPolicy | FieldReadFunction, + pendingJobs?: FieldPolicy | FieldReadFunction, + runningJobs?: FieldPolicy | FieldReadFunction, + skippedCategories?: FieldPolicy | FieldReadFunction, + skippedJobs?: FieldPolicy | FieldReadFunction, + updatingCategories?: FieldPolicy | FieldReadFunction +}; +export type UpdateStatusCategoryTypeKeySpecifier = ('categories' | UpdateStatusCategoryTypeKeySpecifier)[]; +export type UpdateStatusCategoryTypeFieldPolicy = { + categories?: FieldPolicy | FieldReadFunction +}; +export type UpdateStatusTypeKeySpecifier = ('mangas' | UpdateStatusTypeKeySpecifier)[]; +export type UpdateStatusTypeFieldPolicy = { + mangas?: FieldPolicy | FieldReadFunction +}; +export type UpdateStopPayloadKeySpecifier = ('clientMutationId' | UpdateStopPayloadKeySpecifier)[]; +export type UpdateStopPayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction +}; +export type ValidateBackupResultKeySpecifier = ('missingSources' | ValidateBackupResultKeySpecifier)[]; +export type ValidateBackupResultFieldPolicy = { + missingSources?: FieldPolicy | FieldReadFunction +}; +export type ValidateBackupSourceKeySpecifier = ('id' | 'name' | ValidateBackupSourceKeySpecifier)[]; +export type ValidateBackupSourceFieldPolicy = { + id?: FieldPolicy | FieldReadFunction, + name?: FieldPolicy | FieldReadFunction +}; +export type WebUIUpdateInfoKeySpecifier = ('channel' | 'tag' | 'updateAvailable' | WebUIUpdateInfoKeySpecifier)[]; +export type WebUIUpdateInfoFieldPolicy = { + channel?: FieldPolicy | FieldReadFunction, + tag?: FieldPolicy | FieldReadFunction, + updateAvailable?: FieldPolicy | FieldReadFunction +}; +export type WebUIUpdatePayloadKeySpecifier = ('clientMutationId' | 'updateStatus' | WebUIUpdatePayloadKeySpecifier)[]; +export type WebUIUpdatePayloadFieldPolicy = { + clientMutationId?: FieldPolicy | FieldReadFunction, + updateStatus?: FieldPolicy | FieldReadFunction +}; +export type WebUIUpdateStatusKeySpecifier = ('info' | 'progress' | 'state' | WebUIUpdateStatusKeySpecifier)[]; +export type WebUIUpdateStatusFieldPolicy = { + info?: FieldPolicy | FieldReadFunction, + progress?: FieldPolicy | FieldReadFunction, + state?: FieldPolicy | FieldReadFunction +}; +export type StrictTypedTypePolicies = { + AboutPayload?: Omit & { + keyFields?: false | AboutPayloadKeySpecifier | (() => undefined | AboutPayloadKeySpecifier), + fields?: AboutPayloadFieldPolicy, + }, + BackupRestoreStatus?: Omit & { + keyFields?: false | BackupRestoreStatusKeySpecifier | (() => undefined | BackupRestoreStatusKeySpecifier), + fields?: BackupRestoreStatusFieldPolicy, + }, + CategoryEdge?: Omit & { + keyFields?: false | CategoryEdgeKeySpecifier | (() => undefined | CategoryEdgeKeySpecifier), + fields?: CategoryEdgeFieldPolicy, + }, + CategoryMetaType?: Omit & { + keyFields?: false | CategoryMetaTypeKeySpecifier | (() => undefined | CategoryMetaTypeKeySpecifier), + fields?: CategoryMetaTypeFieldPolicy, + }, + CategoryNodeList?: Omit & { + keyFields?: false | CategoryNodeListKeySpecifier | (() => undefined | CategoryNodeListKeySpecifier), + fields?: CategoryNodeListFieldPolicy, + }, + CategoryType?: Omit & { + keyFields?: false | CategoryTypeKeySpecifier | (() => undefined | CategoryTypeKeySpecifier), + fields?: CategoryTypeFieldPolicy, + }, + ChapterEdge?: Omit & { + keyFields?: false | ChapterEdgeKeySpecifier | (() => undefined | ChapterEdgeKeySpecifier), + fields?: ChapterEdgeFieldPolicy, + }, + ChapterMetaType?: Omit & { + keyFields?: false | ChapterMetaTypeKeySpecifier | (() => undefined | ChapterMetaTypeKeySpecifier), + fields?: ChapterMetaTypeFieldPolicy, + }, + ChapterNodeList?: Omit & { + keyFields?: false | ChapterNodeListKeySpecifier | (() => undefined | ChapterNodeListKeySpecifier), + fields?: ChapterNodeListFieldPolicy, + }, + ChapterType?: Omit & { + keyFields?: false | ChapterTypeKeySpecifier | (() => undefined | ChapterTypeKeySpecifier), + fields?: ChapterTypeFieldPolicy, + }, + CheckBoxFilter?: Omit & { + keyFields?: false | CheckBoxFilterKeySpecifier | (() => undefined | CheckBoxFilterKeySpecifier), + fields?: CheckBoxFilterFieldPolicy, + }, + CheckBoxPreference?: Omit & { + keyFields?: false | CheckBoxPreferenceKeySpecifier | (() => undefined | CheckBoxPreferenceKeySpecifier), + fields?: CheckBoxPreferenceFieldPolicy, + }, + CheckForServerUpdatesPayload?: Omit & { + keyFields?: false | CheckForServerUpdatesPayloadKeySpecifier | (() => undefined | CheckForServerUpdatesPayloadKeySpecifier), + fields?: CheckForServerUpdatesPayloadFieldPolicy, + }, + ClearDownloaderPayload?: Omit & { + keyFields?: false | ClearDownloaderPayloadKeySpecifier | (() => undefined | ClearDownloaderPayloadKeySpecifier), + fields?: ClearDownloaderPayloadFieldPolicy, + }, + CreateBackupPayload?: Omit & { + keyFields?: false | CreateBackupPayloadKeySpecifier | (() => undefined | CreateBackupPayloadKeySpecifier), + fields?: CreateBackupPayloadFieldPolicy, + }, + CreateCategoryPayload?: Omit & { + keyFields?: false | CreateCategoryPayloadKeySpecifier | (() => undefined | CreateCategoryPayloadKeySpecifier), + fields?: CreateCategoryPayloadFieldPolicy, + }, + DeleteCategoryMetaPayload?: Omit & { + keyFields?: false | DeleteCategoryMetaPayloadKeySpecifier | (() => undefined | DeleteCategoryMetaPayloadKeySpecifier), + fields?: DeleteCategoryMetaPayloadFieldPolicy, + }, + DeleteCategoryPayload?: Omit & { + keyFields?: false | DeleteCategoryPayloadKeySpecifier | (() => undefined | DeleteCategoryPayloadKeySpecifier), + fields?: DeleteCategoryPayloadFieldPolicy, + }, + DeleteChapterMetaPayload?: Omit & { + keyFields?: false | DeleteChapterMetaPayloadKeySpecifier | (() => undefined | DeleteChapterMetaPayloadKeySpecifier), + fields?: DeleteChapterMetaPayloadFieldPolicy, + }, + DeleteDownloadedChapterPayload?: Omit & { + keyFields?: false | DeleteDownloadedChapterPayloadKeySpecifier | (() => undefined | DeleteDownloadedChapterPayloadKeySpecifier), + fields?: DeleteDownloadedChapterPayloadFieldPolicy, + }, + DeleteDownloadedChaptersPayload?: Omit & { + keyFields?: false | DeleteDownloadedChaptersPayloadKeySpecifier | (() => undefined | DeleteDownloadedChaptersPayloadKeySpecifier), + fields?: DeleteDownloadedChaptersPayloadFieldPolicy, + }, + DeleteGlobalMetaPayload?: Omit & { + keyFields?: false | DeleteGlobalMetaPayloadKeySpecifier | (() => undefined | DeleteGlobalMetaPayloadKeySpecifier), + fields?: DeleteGlobalMetaPayloadFieldPolicy, + }, + DeleteMangaMetaPayload?: Omit & { + keyFields?: false | DeleteMangaMetaPayloadKeySpecifier | (() => undefined | DeleteMangaMetaPayloadKeySpecifier), + fields?: DeleteMangaMetaPayloadFieldPolicy, + }, + DequeueChapterDownloadPayload?: Omit & { + keyFields?: false | DequeueChapterDownloadPayloadKeySpecifier | (() => undefined | DequeueChapterDownloadPayloadKeySpecifier), + fields?: DequeueChapterDownloadPayloadFieldPolicy, + }, + DequeueChapterDownloadsPayload?: Omit & { + keyFields?: false | DequeueChapterDownloadsPayloadKeySpecifier | (() => undefined | DequeueChapterDownloadsPayloadKeySpecifier), + fields?: DequeueChapterDownloadsPayloadFieldPolicy, + }, + DownloadAheadPayload?: Omit & { + keyFields?: false | DownloadAheadPayloadKeySpecifier | (() => undefined | DownloadAheadPayloadKeySpecifier), + fields?: DownloadAheadPayloadFieldPolicy, + }, + DownloadEdge?: Omit & { + keyFields?: false | DownloadEdgeKeySpecifier | (() => undefined | DownloadEdgeKeySpecifier), + fields?: DownloadEdgeFieldPolicy, + }, + DownloadNodeList?: Omit & { + keyFields?: false | DownloadNodeListKeySpecifier | (() => undefined | DownloadNodeListKeySpecifier), + fields?: DownloadNodeListFieldPolicy, + }, + DownloadStatus?: Omit & { + keyFields?: false | DownloadStatusKeySpecifier | (() => undefined | DownloadStatusKeySpecifier), + fields?: DownloadStatusFieldPolicy, + }, + DownloadType?: Omit & { + keyFields?: false | DownloadTypeKeySpecifier | (() => undefined | DownloadTypeKeySpecifier), + fields?: DownloadTypeFieldPolicy, + }, + Edge?: Omit & { + keyFields?: false | EdgeKeySpecifier | (() => undefined | EdgeKeySpecifier), + fields?: EdgeFieldPolicy, + }, + EditTextPreference?: Omit & { + keyFields?: false | EditTextPreferenceKeySpecifier | (() => undefined | EditTextPreferenceKeySpecifier), + fields?: EditTextPreferenceFieldPolicy, + }, + EnqueueChapterDownloadPayload?: Omit & { + keyFields?: false | EnqueueChapterDownloadPayloadKeySpecifier | (() => undefined | EnqueueChapterDownloadPayloadKeySpecifier), + fields?: EnqueueChapterDownloadPayloadFieldPolicy, + }, + EnqueueChapterDownloadsPayload?: Omit & { + keyFields?: false | EnqueueChapterDownloadsPayloadKeySpecifier | (() => undefined | EnqueueChapterDownloadsPayloadKeySpecifier), + fields?: EnqueueChapterDownloadsPayloadFieldPolicy, + }, + ExtensionEdge?: Omit & { + keyFields?: false | ExtensionEdgeKeySpecifier | (() => undefined | ExtensionEdgeKeySpecifier), + fields?: ExtensionEdgeFieldPolicy, + }, + ExtensionNodeList?: Omit & { + keyFields?: false | ExtensionNodeListKeySpecifier | (() => undefined | ExtensionNodeListKeySpecifier), + fields?: ExtensionNodeListFieldPolicy, + }, + ExtensionType?: Omit & { + keyFields?: false | ExtensionTypeKeySpecifier | (() => undefined | ExtensionTypeKeySpecifier), + fields?: ExtensionTypeFieldPolicy, + }, + FetchChapterPagesPayload?: Omit & { + keyFields?: false | FetchChapterPagesPayloadKeySpecifier | (() => undefined | FetchChapterPagesPayloadKeySpecifier), + fields?: FetchChapterPagesPayloadFieldPolicy, + }, + FetchChaptersPayload?: Omit & { + keyFields?: false | FetchChaptersPayloadKeySpecifier | (() => undefined | FetchChaptersPayloadKeySpecifier), + fields?: FetchChaptersPayloadFieldPolicy, + }, + FetchExtensionsPayload?: Omit & { + keyFields?: false | FetchExtensionsPayloadKeySpecifier | (() => undefined | FetchExtensionsPayloadKeySpecifier), + fields?: FetchExtensionsPayloadFieldPolicy, + }, + FetchMangaPayload?: Omit & { + keyFields?: false | FetchMangaPayloadKeySpecifier | (() => undefined | FetchMangaPayloadKeySpecifier), + fields?: FetchMangaPayloadFieldPolicy, + }, + FetchSourceMangaPayload?: Omit & { + keyFields?: false | FetchSourceMangaPayloadKeySpecifier | (() => undefined | FetchSourceMangaPayloadKeySpecifier), + fields?: FetchSourceMangaPayloadFieldPolicy, + }, + GlobalMetaNodeList?: Omit & { + keyFields?: false | GlobalMetaNodeListKeySpecifier | (() => undefined | GlobalMetaNodeListKeySpecifier), + fields?: GlobalMetaNodeListFieldPolicy, + }, + GlobalMetaType?: Omit & { + keyFields?: false | GlobalMetaTypeKeySpecifier | (() => undefined | GlobalMetaTypeKeySpecifier), + fields?: GlobalMetaTypeFieldPolicy, + }, + GroupFilter?: Omit & { + keyFields?: false | GroupFilterKeySpecifier | (() => undefined | GroupFilterKeySpecifier), + fields?: GroupFilterFieldPolicy, + }, + HeaderFilter?: Omit & { + keyFields?: false | HeaderFilterKeySpecifier | (() => undefined | HeaderFilterKeySpecifier), + fields?: HeaderFilterFieldPolicy, + }, + InstallExternalExtensionPayload?: Omit & { + keyFields?: false | InstallExternalExtensionPayloadKeySpecifier | (() => undefined | InstallExternalExtensionPayloadKeySpecifier), + fields?: InstallExternalExtensionPayloadFieldPolicy, + }, + LastUpdateTimestampPayload?: Omit & { + keyFields?: false | LastUpdateTimestampPayloadKeySpecifier | (() => undefined | LastUpdateTimestampPayloadKeySpecifier), + fields?: LastUpdateTimestampPayloadFieldPolicy, + }, + ListPreference?: Omit & { + keyFields?: false | ListPreferenceKeySpecifier | (() => undefined | ListPreferenceKeySpecifier), + fields?: ListPreferenceFieldPolicy, + }, + MangaEdge?: Omit & { + keyFields?: false | MangaEdgeKeySpecifier | (() => undefined | MangaEdgeKeySpecifier), + fields?: MangaEdgeFieldPolicy, + }, + MangaMetaType?: Omit & { + keyFields?: false | MangaMetaTypeKeySpecifier | (() => undefined | MangaMetaTypeKeySpecifier), + fields?: MangaMetaTypeFieldPolicy, + }, + MangaNodeList?: Omit & { + keyFields?: false | MangaNodeListKeySpecifier | (() => undefined | MangaNodeListKeySpecifier), + fields?: MangaNodeListFieldPolicy, + }, + MangaType?: Omit & { + keyFields?: false | MangaTypeKeySpecifier | (() => undefined | MangaTypeKeySpecifier), + fields?: MangaTypeFieldPolicy, + }, + MetaEdge?: Omit & { + keyFields?: false | MetaEdgeKeySpecifier | (() => undefined | MetaEdgeKeySpecifier), + fields?: MetaEdgeFieldPolicy, + }, + MetaType?: Omit & { + keyFields?: false | MetaTypeKeySpecifier | (() => undefined | MetaTypeKeySpecifier), + fields?: MetaTypeFieldPolicy, + }, + MultiSelectListPreference?: Omit & { + keyFields?: false | MultiSelectListPreferenceKeySpecifier | (() => undefined | MultiSelectListPreferenceKeySpecifier), + fields?: MultiSelectListPreferenceFieldPolicy, + }, + Mutation?: Omit & { + keyFields?: false | MutationKeySpecifier | (() => undefined | MutationKeySpecifier), + fields?: MutationFieldPolicy, + }, + NodeList?: Omit & { + keyFields?: false | NodeListKeySpecifier | (() => undefined | NodeListKeySpecifier), + fields?: NodeListFieldPolicy, + }, + PageInfo?: Omit & { + keyFields?: false | PageInfoKeySpecifier | (() => undefined | PageInfoKeySpecifier), + fields?: PageInfoFieldPolicy, + }, + PartialSettingsType?: Omit & { + keyFields?: false | PartialSettingsTypeKeySpecifier | (() => undefined | PartialSettingsTypeKeySpecifier), + fields?: PartialSettingsTypeFieldPolicy, + }, + Query?: Omit & { + keyFields?: false | QueryKeySpecifier | (() => undefined | QueryKeySpecifier), + fields?: QueryFieldPolicy, + }, + ReorderChapterDownloadPayload?: Omit & { + keyFields?: false | ReorderChapterDownloadPayloadKeySpecifier | (() => undefined | ReorderChapterDownloadPayloadKeySpecifier), + fields?: ReorderChapterDownloadPayloadFieldPolicy, + }, + ResetSettingsPayload?: Omit & { + keyFields?: false | ResetSettingsPayloadKeySpecifier | (() => undefined | ResetSettingsPayloadKeySpecifier), + fields?: ResetSettingsPayloadFieldPolicy, + }, + RestoreBackupPayload?: Omit & { + keyFields?: false | RestoreBackupPayloadKeySpecifier | (() => undefined | RestoreBackupPayloadKeySpecifier), + fields?: RestoreBackupPayloadFieldPolicy, + }, + SelectFilter?: Omit & { + keyFields?: false | SelectFilterKeySpecifier | (() => undefined | SelectFilterKeySpecifier), + fields?: SelectFilterFieldPolicy, + }, + SeparatorFilter?: Omit & { + keyFields?: false | SeparatorFilterKeySpecifier | (() => undefined | SeparatorFilterKeySpecifier), + fields?: SeparatorFilterFieldPolicy, + }, + SetCategoryMetaPayload?: Omit & { + keyFields?: false | SetCategoryMetaPayloadKeySpecifier | (() => undefined | SetCategoryMetaPayloadKeySpecifier), + fields?: SetCategoryMetaPayloadFieldPolicy, + }, + SetChapterMetaPayload?: Omit & { + keyFields?: false | SetChapterMetaPayloadKeySpecifier | (() => undefined | SetChapterMetaPayloadKeySpecifier), + fields?: SetChapterMetaPayloadFieldPolicy, + }, + SetGlobalMetaPayload?: Omit & { + keyFields?: false | SetGlobalMetaPayloadKeySpecifier | (() => undefined | SetGlobalMetaPayloadKeySpecifier), + fields?: SetGlobalMetaPayloadFieldPolicy, + }, + SetMangaMetaPayload?: Omit & { + keyFields?: false | SetMangaMetaPayloadKeySpecifier | (() => undefined | SetMangaMetaPayloadKeySpecifier), + fields?: SetMangaMetaPayloadFieldPolicy, + }, + SetSettingsPayload?: Omit & { + keyFields?: false | SetSettingsPayloadKeySpecifier | (() => undefined | SetSettingsPayloadKeySpecifier), + fields?: SetSettingsPayloadFieldPolicy, + }, + Settings?: Omit & { + keyFields?: false | SettingsKeySpecifier | (() => undefined | SettingsKeySpecifier), + fields?: SettingsFieldPolicy, + }, + SettingsType?: Omit & { + keyFields?: false | SettingsTypeKeySpecifier | (() => undefined | SettingsTypeKeySpecifier), + fields?: SettingsTypeFieldPolicy, + }, + SortFilter?: Omit & { + keyFields?: false | SortFilterKeySpecifier | (() => undefined | SortFilterKeySpecifier), + fields?: SortFilterFieldPolicy, + }, + SortSelection?: Omit & { + keyFields?: false | SortSelectionKeySpecifier | (() => undefined | SortSelectionKeySpecifier), + fields?: SortSelectionFieldPolicy, + }, + SourceEdge?: Omit & { + keyFields?: false | SourceEdgeKeySpecifier | (() => undefined | SourceEdgeKeySpecifier), + fields?: SourceEdgeFieldPolicy, + }, + SourceNodeList?: Omit & { + keyFields?: false | SourceNodeListKeySpecifier | (() => undefined | SourceNodeListKeySpecifier), + fields?: SourceNodeListFieldPolicy, + }, + SourceType?: Omit & { + keyFields?: false | SourceTypeKeySpecifier | (() => undefined | SourceTypeKeySpecifier), + fields?: SourceTypeFieldPolicy, + }, + StartDownloaderPayload?: Omit & { + keyFields?: false | StartDownloaderPayloadKeySpecifier | (() => undefined | StartDownloaderPayloadKeySpecifier), + fields?: StartDownloaderPayloadFieldPolicy, + }, + StopDownloaderPayload?: Omit & { + keyFields?: false | StopDownloaderPayloadKeySpecifier | (() => undefined | StopDownloaderPayloadKeySpecifier), + fields?: StopDownloaderPayloadFieldPolicy, + }, + Subscription?: Omit & { + keyFields?: false | SubscriptionKeySpecifier | (() => undefined | SubscriptionKeySpecifier), + fields?: SubscriptionFieldPolicy, + }, + SwitchPreference?: Omit & { + keyFields?: false | SwitchPreferenceKeySpecifier | (() => undefined | SwitchPreferenceKeySpecifier), + fields?: SwitchPreferenceFieldPolicy, + }, + TextFilter?: Omit & { + keyFields?: false | TextFilterKeySpecifier | (() => undefined | TextFilterKeySpecifier), + fields?: TextFilterFieldPolicy, + }, + TriStateFilter?: Omit & { + keyFields?: false | TriStateFilterKeySpecifier | (() => undefined | TriStateFilterKeySpecifier), + fields?: TriStateFilterFieldPolicy, + }, + UpdateCategoriesPayload?: Omit & { + keyFields?: false | UpdateCategoriesPayloadKeySpecifier | (() => undefined | UpdateCategoriesPayloadKeySpecifier), + fields?: UpdateCategoriesPayloadFieldPolicy, + }, + UpdateCategoryMangaPayload?: Omit & { + keyFields?: false | UpdateCategoryMangaPayloadKeySpecifier | (() => undefined | UpdateCategoryMangaPayloadKeySpecifier), + fields?: UpdateCategoryMangaPayloadFieldPolicy, + }, + UpdateCategoryOrderPayload?: Omit & { + keyFields?: false | UpdateCategoryOrderPayloadKeySpecifier | (() => undefined | UpdateCategoryOrderPayloadKeySpecifier), + fields?: UpdateCategoryOrderPayloadFieldPolicy, + }, + UpdateCategoryPayload?: Omit & { + keyFields?: false | UpdateCategoryPayloadKeySpecifier | (() => undefined | UpdateCategoryPayloadKeySpecifier), + fields?: UpdateCategoryPayloadFieldPolicy, + }, + UpdateChapterPayload?: Omit & { + keyFields?: false | UpdateChapterPayloadKeySpecifier | (() => undefined | UpdateChapterPayloadKeySpecifier), + fields?: UpdateChapterPayloadFieldPolicy, + }, + UpdateChaptersPayload?: Omit & { + keyFields?: false | UpdateChaptersPayloadKeySpecifier | (() => undefined | UpdateChaptersPayloadKeySpecifier), + fields?: UpdateChaptersPayloadFieldPolicy, + }, + UpdateExtensionPayload?: Omit & { + keyFields?: false | UpdateExtensionPayloadKeySpecifier | (() => undefined | UpdateExtensionPayloadKeySpecifier), + fields?: UpdateExtensionPayloadFieldPolicy, + }, + UpdateExtensionsPayload?: Omit & { + keyFields?: false | UpdateExtensionsPayloadKeySpecifier | (() => undefined | UpdateExtensionsPayloadKeySpecifier), + fields?: UpdateExtensionsPayloadFieldPolicy, + }, + UpdateLibraryMangaPayload?: Omit & { + keyFields?: false | UpdateLibraryMangaPayloadKeySpecifier | (() => undefined | UpdateLibraryMangaPayloadKeySpecifier), + fields?: UpdateLibraryMangaPayloadFieldPolicy, + }, + UpdateMangaCategoriesPayload?: Omit & { + keyFields?: false | UpdateMangaCategoriesPayloadKeySpecifier | (() => undefined | UpdateMangaCategoriesPayloadKeySpecifier), + fields?: UpdateMangaCategoriesPayloadFieldPolicy, + }, + UpdateMangaPayload?: Omit & { + keyFields?: false | UpdateMangaPayloadKeySpecifier | (() => undefined | UpdateMangaPayloadKeySpecifier), + fields?: UpdateMangaPayloadFieldPolicy, + }, + UpdateMangasCategoriesPayload?: Omit & { + keyFields?: false | UpdateMangasCategoriesPayloadKeySpecifier | (() => undefined | UpdateMangasCategoriesPayloadKeySpecifier), + fields?: UpdateMangasCategoriesPayloadFieldPolicy, + }, + UpdateMangasPayload?: Omit & { + keyFields?: false | UpdateMangasPayloadKeySpecifier | (() => undefined | UpdateMangasPayloadKeySpecifier), + fields?: UpdateMangasPayloadFieldPolicy, + }, + UpdateSourcePreferencePayload?: Omit & { + keyFields?: false | UpdateSourcePreferencePayloadKeySpecifier | (() => undefined | UpdateSourcePreferencePayloadKeySpecifier), + fields?: UpdateSourcePreferencePayloadFieldPolicy, + }, + UpdateStatus?: Omit & { + keyFields?: false | UpdateStatusKeySpecifier | (() => undefined | UpdateStatusKeySpecifier), + fields?: UpdateStatusFieldPolicy, + }, + UpdateStatusCategoryType?: Omit & { + keyFields?: false | UpdateStatusCategoryTypeKeySpecifier | (() => undefined | UpdateStatusCategoryTypeKeySpecifier), + fields?: UpdateStatusCategoryTypeFieldPolicy, + }, + UpdateStatusType?: Omit & { + keyFields?: false | UpdateStatusTypeKeySpecifier | (() => undefined | UpdateStatusTypeKeySpecifier), + fields?: UpdateStatusTypeFieldPolicy, + }, + UpdateStopPayload?: Omit & { + keyFields?: false | UpdateStopPayloadKeySpecifier | (() => undefined | UpdateStopPayloadKeySpecifier), + fields?: UpdateStopPayloadFieldPolicy, + }, + ValidateBackupResult?: Omit & { + keyFields?: false | ValidateBackupResultKeySpecifier | (() => undefined | ValidateBackupResultKeySpecifier), + fields?: ValidateBackupResultFieldPolicy, + }, + ValidateBackupSource?: Omit & { + keyFields?: false | ValidateBackupSourceKeySpecifier | (() => undefined | ValidateBackupSourceKeySpecifier), + fields?: ValidateBackupSourceFieldPolicy, + }, + WebUIUpdateInfo?: Omit & { + keyFields?: false | WebUIUpdateInfoKeySpecifier | (() => undefined | WebUIUpdateInfoKeySpecifier), + fields?: WebUIUpdateInfoFieldPolicy, + }, + WebUIUpdatePayload?: Omit & { + keyFields?: false | WebUIUpdatePayloadKeySpecifier | (() => undefined | WebUIUpdatePayloadKeySpecifier), + fields?: WebUIUpdatePayloadFieldPolicy, + }, + WebUIUpdateStatus?: Omit & { + keyFields?: false | WebUIUpdateStatusKeySpecifier | (() => undefined | WebUIUpdateStatusKeySpecifier), + fields?: WebUIUpdateStatusFieldPolicy, + } +}; +export type TypedTypePolicies = StrictTypedTypePolicies & TypePolicies; \ No newline at end of file diff --git a/src/lib/graphql/generated/graphql.ts b/src/lib/graphql/generated/graphql.ts new file mode 100644 index 00000000..56da130b --- /dev/null +++ b/src/lib/graphql/generated/graphql.ts @@ -0,0 +1,2605 @@ +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + Cursor: { input: string; output: string; } + LongString: { input: string; output: string; } + Upload: { input: any; output: any; } +}; + +export type AboutPayload = { + __typename?: 'AboutPayload'; + buildTime: Scalars['LongString']['output']; + buildType: Scalars['String']['output']; + discord: Scalars['String']['output']; + github: Scalars['String']['output']; + name: Scalars['String']['output']; + revision: Scalars['String']['output']; + version: Scalars['String']['output']; +}; + +export enum BackupRestoreState { + Idle = 'IDLE', + RestoringCategories = 'RESTORING_CATEGORIES', + RestoringManga = 'RESTORING_MANGA' +} + +export type BackupRestoreStatus = { + __typename?: 'BackupRestoreStatus'; + mangaProgress: Scalars['Int']['output']; + state: BackupRestoreState; + totalManga: Scalars['Int']['output']; +}; + +export type BooleanFilterInput = { + distinctFrom?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + in?: InputMaybe>; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + notDistinctFrom?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type CategoryConditionInput = { + default?: InputMaybe; + id?: InputMaybe; + name?: InputMaybe; + order?: InputMaybe; +}; + +export type CategoryEdge = Edge & { + __typename?: 'CategoryEdge'; + cursor: Scalars['Cursor']['output']; + node: CategoryType; +}; + +export type CategoryFilterInput = { + and?: InputMaybe>; + default?: InputMaybe; + id?: InputMaybe; + name?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; + order?: InputMaybe; +}; + +export type CategoryMetaType = MetaType & { + __typename?: 'CategoryMetaType'; + category: CategoryType; + categoryId: Scalars['Int']['output']; + key: Scalars['String']['output']; + value: Scalars['String']['output']; +}; + +export type CategoryMetaTypeInput = { + categoryId: Scalars['Int']['input']; + key: Scalars['String']['input']; + value: Scalars['String']['input']; +}; + +export type CategoryNodeList = NodeList & { + __typename?: 'CategoryNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum CategoryOrderBy { + Id = 'ID', + Name = 'NAME', + Order = 'ORDER' +} + +export type CategoryType = { + __typename?: 'CategoryType'; + default: Scalars['Boolean']['output']; + id: Scalars['Int']['output']; + includeInUpdate: IncludeInUpdate; + mangas: MangaNodeList; + meta: Array; + name: Scalars['String']['output']; + order: Scalars['Int']['output']; +}; + +export type ChapterConditionInput = { + chapterNumber?: InputMaybe; + fetchedAt?: InputMaybe; + id?: InputMaybe; + isBookmarked?: InputMaybe; + isDownloaded?: InputMaybe; + isRead?: InputMaybe; + lastPageRead?: InputMaybe; + lastReadAt?: InputMaybe; + mangaId?: InputMaybe; + name?: InputMaybe; + pageCount?: InputMaybe; + realUrl?: InputMaybe; + scanlator?: InputMaybe; + sourceOrder?: InputMaybe; + uploadDate?: InputMaybe; + url?: InputMaybe; +}; + +export type ChapterEdge = Edge & { + __typename?: 'ChapterEdge'; + cursor: Scalars['Cursor']['output']; + node: ChapterType; +}; + +export type ChapterFilterInput = { + and?: InputMaybe>; + chapterNumber?: InputMaybe; + fetchedAt?: InputMaybe; + id?: InputMaybe; + inLibrary?: InputMaybe; + isBookmarked?: InputMaybe; + isDownloaded?: InputMaybe; + isRead?: InputMaybe; + lastPageRead?: InputMaybe; + lastReadAt?: InputMaybe; + mangaId?: InputMaybe; + name?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; + pageCount?: InputMaybe; + realUrl?: InputMaybe; + scanlator?: InputMaybe; + sourceOrder?: InputMaybe; + uploadDate?: InputMaybe; + url?: InputMaybe; +}; + +export type ChapterMetaType = MetaType & { + __typename?: 'ChapterMetaType'; + chapter: ChapterType; + chapterId: Scalars['Int']['output']; + key: Scalars['String']['output']; + value: Scalars['String']['output']; +}; + +export type ChapterMetaTypeInput = { + chapterId: Scalars['Int']['input']; + key: Scalars['String']['input']; + value: Scalars['String']['input']; +}; + +export type ChapterNodeList = NodeList & { + __typename?: 'ChapterNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum ChapterOrderBy { + ChapterNumber = 'CHAPTER_NUMBER', + FetchedAt = 'FETCHED_AT', + Id = 'ID', + LastReadAt = 'LAST_READ_AT', + Name = 'NAME', + SourceOrder = 'SOURCE_ORDER', + UploadDate = 'UPLOAD_DATE' +} + +export type ChapterType = { + __typename?: 'ChapterType'; + chapterNumber: Scalars['Float']['output']; + fetchedAt: Scalars['LongString']['output']; + id: Scalars['Int']['output']; + isBookmarked: Scalars['Boolean']['output']; + isDownloaded: Scalars['Boolean']['output']; + isRead: Scalars['Boolean']['output']; + lastPageRead: Scalars['Int']['output']; + lastReadAt: Scalars['LongString']['output']; + manga: MangaType; + mangaId: Scalars['Int']['output']; + meta: Array; + name: Scalars['String']['output']; + pageCount: Scalars['Int']['output']; + realUrl?: Maybe; + scanlator?: Maybe; + sourceOrder: Scalars['Int']['output']; + uploadDate: Scalars['LongString']['output']; + url: Scalars['String']['output']; +}; + +export type CheckBoxFilter = { + __typename?: 'CheckBoxFilter'; + default: Scalars['Boolean']['output']; + name: Scalars['String']['output']; +}; + +export type CheckBoxPreference = { + __typename?: 'CheckBoxPreference'; + currentValue?: Maybe; + default: Scalars['Boolean']['output']; + key: Scalars['String']['output']; + summary?: Maybe; + title: Scalars['String']['output']; + visible: Scalars['Boolean']['output']; +}; + +export type CheckForServerUpdatesPayload = { + __typename?: 'CheckForServerUpdatesPayload'; + channel: Scalars['String']['output']; + tag: Scalars['String']['output']; + url: Scalars['String']['output']; +}; + +export type ClearDownloaderInput = { + clientMutationId?: InputMaybe; +}; + +export type ClearDownloaderPayload = { + __typename?: 'ClearDownloaderPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type CreateBackupInput = { + clientMutationId?: InputMaybe; + includeCategories?: InputMaybe; + includeChapters?: InputMaybe; +}; + +export type CreateBackupPayload = { + __typename?: 'CreateBackupPayload'; + clientMutationId?: Maybe; + url: Scalars['String']['output']; +}; + +export type CreateCategoryInput = { + clientMutationId?: InputMaybe; + default?: InputMaybe; + includeInUpdate?: InputMaybe; + name: Scalars['String']['input']; + order?: InputMaybe; +}; + +export type CreateCategoryPayload = { + __typename?: 'CreateCategoryPayload'; + category: CategoryType; + clientMutationId?: Maybe; +}; + +export type DeleteCategoryInput = { + categoryId: Scalars['Int']['input']; + clientMutationId?: InputMaybe; +}; + +export type DeleteCategoryMetaInput = { + categoryId: Scalars['Int']['input']; + clientMutationId?: InputMaybe; + key: Scalars['String']['input']; +}; + +export type DeleteCategoryMetaPayload = { + __typename?: 'DeleteCategoryMetaPayload'; + category: CategoryType; + clientMutationId?: Maybe; + meta?: Maybe; +}; + +export type DeleteCategoryPayload = { + __typename?: 'DeleteCategoryPayload'; + category?: Maybe; + clientMutationId?: Maybe; + mangas: Array; +}; + +export type DeleteChapterMetaInput = { + chapterId: Scalars['Int']['input']; + clientMutationId?: InputMaybe; + key: Scalars['String']['input']; +}; + +export type DeleteChapterMetaPayload = { + __typename?: 'DeleteChapterMetaPayload'; + chapter: ChapterType; + clientMutationId?: Maybe; + meta?: Maybe; +}; + +export type DeleteDownloadedChapterInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; +}; + +export type DeleteDownloadedChapterPayload = { + __typename?: 'DeleteDownloadedChapterPayload'; + chapters: ChapterType; + clientMutationId?: Maybe; +}; + +export type DeleteDownloadedChaptersInput = { + clientMutationId?: InputMaybe; + ids: Array; +}; + +export type DeleteDownloadedChaptersPayload = { + __typename?: 'DeleteDownloadedChaptersPayload'; + chapters: Array; + clientMutationId?: Maybe; +}; + +export type DeleteGlobalMetaInput = { + clientMutationId?: InputMaybe; + key: Scalars['String']['input']; +}; + +export type DeleteGlobalMetaPayload = { + __typename?: 'DeleteGlobalMetaPayload'; + clientMutationId?: Maybe; + meta?: Maybe; +}; + +export type DeleteMangaMetaInput = { + clientMutationId?: InputMaybe; + key: Scalars['String']['input']; + mangaId: Scalars['Int']['input']; +}; + +export type DeleteMangaMetaPayload = { + __typename?: 'DeleteMangaMetaPayload'; + clientMutationId?: Maybe; + manga: MangaType; + meta?: Maybe; +}; + +export type DequeueChapterDownloadInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; +}; + +export type DequeueChapterDownloadPayload = { + __typename?: 'DequeueChapterDownloadPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type DequeueChapterDownloadsInput = { + clientMutationId?: InputMaybe; + ids: Array; +}; + +export type DequeueChapterDownloadsPayload = { + __typename?: 'DequeueChapterDownloadsPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type DownloadAheadInput = { + clientMutationId?: InputMaybe; + latestReadChapterIds?: InputMaybe>; + mangaIds: Array; +}; + +export type DownloadAheadPayload = { + __typename?: 'DownloadAheadPayload'; + clientMutationId?: Maybe; +}; + +export type DownloadEdge = Edge & { + __typename?: 'DownloadEdge'; + cursor: Scalars['Cursor']['output']; + node: DownloadType; +}; + +export type DownloadNodeList = NodeList & { + __typename?: 'DownloadNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum DownloadState { + Downloading = 'DOWNLOADING', + Error = 'ERROR', + Finished = 'FINISHED', + Queued = 'QUEUED' +} + +export type DownloadStatus = { + __typename?: 'DownloadStatus'; + queue: Array; + state: DownloaderState; +}; + +export type DownloadType = { + __typename?: 'DownloadType'; + chapter: ChapterType; + manga: MangaType; + progress: Scalars['Float']['output']; + state: DownloadState; + tries: Scalars['Int']['output']; +}; + +export enum DownloaderState { + Started = 'STARTED', + Stopped = 'STOPPED' +} + +export type Edge = { + /** A cursor for use in pagination. */ + cursor: Scalars['Cursor']['output']; + /** The [T] at the end of the edge. */ + node: Node; +}; + +export type EditTextPreference = { + __typename?: 'EditTextPreference'; + currentValue?: Maybe; + default?: Maybe; + dialogMessage?: Maybe; + dialogTitle?: Maybe; + key: Scalars['String']['output']; + summary?: Maybe; + text?: Maybe; + title?: Maybe; + visible: Scalars['Boolean']['output']; +}; + +export type EnqueueChapterDownloadInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; +}; + +export type EnqueueChapterDownloadPayload = { + __typename?: 'EnqueueChapterDownloadPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type EnqueueChapterDownloadsInput = { + clientMutationId?: InputMaybe; + ids: Array; +}; + +export type EnqueueChapterDownloadsPayload = { + __typename?: 'EnqueueChapterDownloadsPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type ExtensionConditionInput = { + apkName?: InputMaybe; + hasUpdate?: InputMaybe; + iconUrl?: InputMaybe; + isInstalled?: InputMaybe; + isNsfw?: InputMaybe; + isObsolete?: InputMaybe; + lang?: InputMaybe; + name?: InputMaybe; + pkgName?: InputMaybe; + versionCode?: InputMaybe; + versionName?: InputMaybe; +}; + +export type ExtensionEdge = Edge & { + __typename?: 'ExtensionEdge'; + cursor: Scalars['Cursor']['output']; + node: ExtensionType; +}; + +export type ExtensionFilterInput = { + and?: InputMaybe>; + apkName?: InputMaybe; + hasUpdate?: InputMaybe; + iconUrl?: InputMaybe; + isInstalled?: InputMaybe; + isNsfw?: InputMaybe; + isObsolete?: InputMaybe; + lang?: InputMaybe; + name?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; + pkgName?: InputMaybe; + versionCode?: InputMaybe; + versionName?: InputMaybe; +}; + +export type ExtensionNodeList = NodeList & { + __typename?: 'ExtensionNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum ExtensionOrderBy { + ApkName = 'APK_NAME', + Name = 'NAME', + PkgName = 'PKG_NAME' +} + +export type ExtensionType = { + __typename?: 'ExtensionType'; + apkName: Scalars['String']['output']; + hasUpdate: Scalars['Boolean']['output']; + iconUrl: Scalars['String']['output']; + isInstalled: Scalars['Boolean']['output']; + isNsfw: Scalars['Boolean']['output']; + isObsolete: Scalars['Boolean']['output']; + lang: Scalars['String']['output']; + name: Scalars['String']['output']; + pkgName: Scalars['String']['output']; + source: SourceNodeList; + versionCode: Scalars['Int']['output']; + versionName: Scalars['String']['output']; +}; + +export type FetchChapterPagesInput = { + chapterId: Scalars['Int']['input']; + clientMutationId?: InputMaybe; +}; + +export type FetchChapterPagesPayload = { + __typename?: 'FetchChapterPagesPayload'; + chapter: ChapterType; + clientMutationId?: Maybe; + pages: Array; +}; + +export type FetchChaptersInput = { + clientMutationId?: InputMaybe; + mangaId: Scalars['Int']['input']; +}; + +export type FetchChaptersPayload = { + __typename?: 'FetchChaptersPayload'; + chapters: Array; + clientMutationId?: Maybe; +}; + +export type FetchExtensionsInput = { + clientMutationId?: InputMaybe; +}; + +export type FetchExtensionsPayload = { + __typename?: 'FetchExtensionsPayload'; + clientMutationId?: Maybe; + extensions: Array; +}; + +export type FetchMangaInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; +}; + +export type FetchMangaPayload = { + __typename?: 'FetchMangaPayload'; + clientMutationId?: Maybe; + manga: MangaType; +}; + +export type FetchSourceMangaInput = { + clientMutationId?: InputMaybe; + filters?: InputMaybe>; + page: Scalars['Int']['input']; + query?: InputMaybe; + source: Scalars['LongString']['input']; + type: FetchSourceMangaType; +}; + +export type FetchSourceMangaPayload = { + __typename?: 'FetchSourceMangaPayload'; + clientMutationId?: Maybe; + hasNextPage: Scalars['Boolean']['output']; + mangas: Array; +}; + +export enum FetchSourceMangaType { + Latest = 'LATEST', + Popular = 'POPULAR', + Search = 'SEARCH' +} + +export type Filter = CheckBoxFilter | GroupFilter | HeaderFilter | SelectFilter | SeparatorFilter | SortFilter | TextFilter | TriStateFilter; + +export type FilterChangeInput = { + checkBoxState?: InputMaybe; + groupChange?: InputMaybe; + position: Scalars['Int']['input']; + selectState?: InputMaybe; + sortState?: InputMaybe; + textState?: InputMaybe; + triState?: InputMaybe; +}; + +export type FloatFilterInput = { + distinctFrom?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + in?: InputMaybe>; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + notDistinctFrom?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type GlobalMetaNodeList = NodeList & { + __typename?: 'GlobalMetaNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export type GlobalMetaType = MetaType & { + __typename?: 'GlobalMetaType'; + key: Scalars['String']['output']; + value: Scalars['String']['output']; +}; + +export type GlobalMetaTypeInput = { + key: Scalars['String']['input']; + value: Scalars['String']['input']; +}; + +export type GroupFilter = { + __typename?: 'GroupFilter'; + filters: Array; + name: Scalars['String']['output']; +}; + +export type HeaderFilter = { + __typename?: 'HeaderFilter'; + name: Scalars['String']['output']; +}; + +export enum IncludeInUpdate { + Exclude = 'EXCLUDE', + Include = 'INCLUDE', + Unset = 'UNSET' +} + +export type InstallExternalExtensionInput = { + clientMutationId?: InputMaybe; + extensionFile: Scalars['Upload']['input']; +}; + +export type InstallExternalExtensionPayload = { + __typename?: 'InstallExternalExtensionPayload'; + clientMutationId?: Maybe; + extension: ExtensionType; +}; + +export type IntFilterInput = { + distinctFrom?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + in?: InputMaybe>; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + notDistinctFrom?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type LastUpdateTimestampPayload = { + __typename?: 'LastUpdateTimestampPayload'; + timestamp: Scalars['LongString']['output']; +}; + +export type ListPreference = { + __typename?: 'ListPreference'; + currentValue?: Maybe; + default?: Maybe; + entries: Array; + entryValues: Array; + key: Scalars['String']['output']; + summary?: Maybe; + title?: Maybe; + visible: Scalars['Boolean']['output']; +}; + +export type LongFilterInput = { + distinctFrom?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + in?: InputMaybe>; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + notDistinctFrom?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type MangaConditionInput = { + artist?: InputMaybe; + author?: InputMaybe; + categoryIds?: InputMaybe>; + chaptersLastFetchedAt?: InputMaybe; + description?: InputMaybe; + genre?: InputMaybe>; + id?: InputMaybe; + inLibrary?: InputMaybe; + inLibraryAt?: InputMaybe; + initialized?: InputMaybe; + lastFetchedAt?: InputMaybe; + realUrl?: InputMaybe; + sourceId?: InputMaybe; + status?: InputMaybe; + thumbnailUrl?: InputMaybe; + title?: InputMaybe; + url?: InputMaybe; +}; + +export type MangaEdge = Edge & { + __typename?: 'MangaEdge'; + cursor: Scalars['Cursor']['output']; + node: MangaType; +}; + +export type MangaFilterInput = { + and?: InputMaybe>; + artist?: InputMaybe; + author?: InputMaybe; + categoryId?: InputMaybe; + chaptersLastFetchedAt?: InputMaybe; + description?: InputMaybe; + genre?: InputMaybe; + id?: InputMaybe; + inLibrary?: InputMaybe; + inLibraryAt?: InputMaybe; + initialized?: InputMaybe; + lastFetchedAt?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; + realUrl?: InputMaybe; + sourceId?: InputMaybe; + status?: InputMaybe; + thumbnailUrl?: InputMaybe; + title?: InputMaybe; + url?: InputMaybe; +}; + +export type MangaMetaType = MetaType & { + __typename?: 'MangaMetaType'; + key: Scalars['String']['output']; + manga: MangaType; + mangaId: Scalars['Int']['output']; + value: Scalars['String']['output']; +}; + +export type MangaMetaTypeInput = { + key: Scalars['String']['input']; + mangaId: Scalars['Int']['input']; + value: Scalars['String']['input']; +}; + +export type MangaNodeList = NodeList & { + __typename?: 'MangaNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum MangaOrderBy { + Id = 'ID', + InLibraryAt = 'IN_LIBRARY_AT', + LastFetchedAt = 'LAST_FETCHED_AT', + Title = 'TITLE' +} + +export enum MangaStatus { + Cancelled = 'CANCELLED', + Completed = 'COMPLETED', + Licensed = 'LICENSED', + Ongoing = 'ONGOING', + OnHiatus = 'ON_HIATUS', + PublishingFinished = 'PUBLISHING_FINISHED', + Unknown = 'UNKNOWN' +} + +export type MangaStatusFilterInput = { + distinctFrom?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + in?: InputMaybe>; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + notDistinctFrom?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type MangaType = { + __typename?: 'MangaType'; + age?: Maybe; + artist?: Maybe; + author?: Maybe; + categories: CategoryNodeList; + chapters: ChapterNodeList; + chaptersAge?: Maybe; + chaptersLastFetchedAt?: Maybe; + description?: Maybe; + downloadCount: Scalars['Int']['output']; + genre: Array; + id: Scalars['Int']['output']; + inLibrary: Scalars['Boolean']['output']; + inLibraryAt: Scalars['LongString']['output']; + initialized: Scalars['Boolean']['output']; + lastFetchedAt?: Maybe; + lastReadChapter?: Maybe; + meta: Array; + realUrl?: Maybe; + source?: Maybe; + sourceId: Scalars['LongString']['output']; + status: MangaStatus; + thumbnailUrl?: Maybe; + title: Scalars['String']['output']; + unreadCount: Scalars['Int']['output']; + url: Scalars['String']['output']; +}; + +export type MetaConditionInput = { + key?: InputMaybe; + value?: InputMaybe; +}; + +export type MetaEdge = Edge & { + __typename?: 'MetaEdge'; + cursor: Scalars['Cursor']['output']; + node: GlobalMetaType; +}; + +export type MetaFilterInput = { + and?: InputMaybe>; + key?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; + value?: InputMaybe; +}; + +export enum MetaOrderBy { + Key = 'KEY', + Value = 'VALUE' +} + +export type MetaType = { + key: Scalars['String']['output']; + value: Scalars['String']['output']; +}; + +export type MultiSelectListPreference = { + __typename?: 'MultiSelectListPreference'; + currentValue?: Maybe>; + default?: Maybe>; + dialogMessage?: Maybe; + dialogTitle?: Maybe; + entries: Array; + entryValues: Array; + key: Scalars['String']['output']; + summary?: Maybe; + title?: Maybe; + visible: Scalars['Boolean']['output']; +}; + +export type Mutation = { + __typename?: 'Mutation'; + clearDownloader: ClearDownloaderPayload; + createBackup: CreateBackupPayload; + createCategory: CreateCategoryPayload; + deleteCategory: DeleteCategoryPayload; + deleteCategoryMeta: DeleteCategoryMetaPayload; + deleteChapterMeta: DeleteChapterMetaPayload; + deleteDownloadedChapter: DeleteDownloadedChapterPayload; + deleteDownloadedChapters: DeleteDownloadedChaptersPayload; + deleteGlobalMeta: DeleteGlobalMetaPayload; + deleteMangaMeta: DeleteMangaMetaPayload; + dequeueChapterDownload: DequeueChapterDownloadPayload; + dequeueChapterDownloads: DequeueChapterDownloadsPayload; + downloadAhead: DownloadAheadPayload; + enqueueChapterDownload: EnqueueChapterDownloadPayload; + enqueueChapterDownloads: EnqueueChapterDownloadsPayload; + fetchChapterPages: FetchChapterPagesPayload; + fetchChapters: FetchChaptersPayload; + fetchExtensions: FetchExtensionsPayload; + fetchManga: FetchMangaPayload; + fetchSourceManga: FetchSourceMangaPayload; + installExternalExtension: InstallExternalExtensionPayload; + reorderChapterDownload: ReorderChapterDownloadPayload; + resetSettings: ResetSettingsPayload; + restoreBackup: RestoreBackupPayload; + setCategoryMeta: SetCategoryMetaPayload; + setChapterMeta: SetChapterMetaPayload; + setGlobalMeta: SetGlobalMetaPayload; + setMangaMeta: SetMangaMetaPayload; + setSettings: SetSettingsPayload; + startDownloader: StartDownloaderPayload; + stopDownloader: StopDownloaderPayload; + updateCategories: UpdateCategoriesPayload; + updateCategory: UpdateCategoryPayload; + updateCategoryManga: UpdateCategoryMangaPayload; + updateCategoryOrder: UpdateCategoryOrderPayload; + updateChapter: UpdateChapterPayload; + updateChapters: UpdateChaptersPayload; + updateExtension: UpdateExtensionPayload; + updateExtensions: UpdateExtensionsPayload; + updateLibraryManga: UpdateLibraryMangaPayload; + updateManga: UpdateMangaPayload; + updateMangaCategories: UpdateMangaCategoriesPayload; + updateMangas: UpdateMangasPayload; + updateMangasCategories: UpdateMangasCategoriesPayload; + updateSourcePreference: UpdateSourcePreferencePayload; + updateStop: UpdateStopPayload; + updateWebUI: WebUiUpdatePayload; +}; + + +export type MutationClearDownloaderArgs = { + input: ClearDownloaderInput; +}; + + +export type MutationCreateBackupArgs = { + input?: InputMaybe; +}; + + +export type MutationCreateCategoryArgs = { + input: CreateCategoryInput; +}; + + +export type MutationDeleteCategoryArgs = { + input: DeleteCategoryInput; +}; + + +export type MutationDeleteCategoryMetaArgs = { + input: DeleteCategoryMetaInput; +}; + + +export type MutationDeleteChapterMetaArgs = { + input: DeleteChapterMetaInput; +}; + + +export type MutationDeleteDownloadedChapterArgs = { + input: DeleteDownloadedChapterInput; +}; + + +export type MutationDeleteDownloadedChaptersArgs = { + input: DeleteDownloadedChaptersInput; +}; + + +export type MutationDeleteGlobalMetaArgs = { + input: DeleteGlobalMetaInput; +}; + + +export type MutationDeleteMangaMetaArgs = { + input: DeleteMangaMetaInput; +}; + + +export type MutationDequeueChapterDownloadArgs = { + input: DequeueChapterDownloadInput; +}; + + +export type MutationDequeueChapterDownloadsArgs = { + input: DequeueChapterDownloadsInput; +}; + + +export type MutationDownloadAheadArgs = { + input: DownloadAheadInput; +}; + + +export type MutationEnqueueChapterDownloadArgs = { + input: EnqueueChapterDownloadInput; +}; + + +export type MutationEnqueueChapterDownloadsArgs = { + input: EnqueueChapterDownloadsInput; +}; + + +export type MutationFetchChapterPagesArgs = { + input: FetchChapterPagesInput; +}; + + +export type MutationFetchChaptersArgs = { + input: FetchChaptersInput; +}; + + +export type MutationFetchExtensionsArgs = { + input: FetchExtensionsInput; +}; + + +export type MutationFetchMangaArgs = { + input: FetchMangaInput; +}; + + +export type MutationFetchSourceMangaArgs = { + input: FetchSourceMangaInput; +}; + + +export type MutationInstallExternalExtensionArgs = { + input: InstallExternalExtensionInput; +}; + + +export type MutationReorderChapterDownloadArgs = { + input: ReorderChapterDownloadInput; +}; + + +export type MutationResetSettingsArgs = { + input: ResetSettingsInput; +}; + + +export type MutationRestoreBackupArgs = { + input: RestoreBackupInput; +}; + + +export type MutationSetCategoryMetaArgs = { + input: SetCategoryMetaInput; +}; + + +export type MutationSetChapterMetaArgs = { + input: SetChapterMetaInput; +}; + + +export type MutationSetGlobalMetaArgs = { + input: SetGlobalMetaInput; +}; + + +export type MutationSetMangaMetaArgs = { + input: SetMangaMetaInput; +}; + + +export type MutationSetSettingsArgs = { + input: SetSettingsInput; +}; + + +export type MutationStartDownloaderArgs = { + input: StartDownloaderInput; +}; + + +export type MutationStopDownloaderArgs = { + input: StopDownloaderInput; +}; + + +export type MutationUpdateCategoriesArgs = { + input: UpdateCategoriesInput; +}; + + +export type MutationUpdateCategoryArgs = { + input: UpdateCategoryInput; +}; + + +export type MutationUpdateCategoryMangaArgs = { + input: UpdateCategoryMangaInput; +}; + + +export type MutationUpdateCategoryOrderArgs = { + input: UpdateCategoryOrderInput; +}; + + +export type MutationUpdateChapterArgs = { + input: UpdateChapterInput; +}; + + +export type MutationUpdateChaptersArgs = { + input: UpdateChaptersInput; +}; + + +export type MutationUpdateExtensionArgs = { + input: UpdateExtensionInput; +}; + + +export type MutationUpdateExtensionsArgs = { + input: UpdateExtensionsInput; +}; + + +export type MutationUpdateLibraryMangaArgs = { + input: UpdateLibraryMangaInput; +}; + + +export type MutationUpdateMangaArgs = { + input: UpdateMangaInput; +}; + + +export type MutationUpdateMangaCategoriesArgs = { + input: UpdateMangaCategoriesInput; +}; + + +export type MutationUpdateMangasArgs = { + input: UpdateMangasInput; +}; + + +export type MutationUpdateMangasCategoriesArgs = { + input: UpdateMangasCategoriesInput; +}; + + +export type MutationUpdateSourcePreferenceArgs = { + input: UpdateSourcePreferenceInput; +}; + + +export type MutationUpdateStopArgs = { + input: UpdateStopInput; +}; + + +export type MutationUpdateWebUiArgs = { + input: WebUiUpdateInput; +}; + +export type Node = CategoryMetaType | CategoryType | ChapterMetaType | ChapterType | DownloadType | ExtensionType | GlobalMetaType | MangaMetaType | MangaType | PartialSettingsType | SettingsType | SourceType; + +export type NodeList = { + /** A list of edges which contains the [T] and cursor to aid in pagination. */ + edges: Array; + /** A list of [T] objects. */ + nodes: Array; + /** Information to aid in pagination. */ + pageInfo: PageInfo; + /** The count of all nodes you could get from the connection. */ + totalCount: Scalars['Int']['output']; +}; + +export type PageInfo = { + __typename?: 'PageInfo'; + /** When paginating forwards, the cursor to continue. */ + endCursor?: Maybe; + /** When paginating forwards, are there more items? */ + hasNextPage: Scalars['Boolean']['output']; + /** When paginating backwards, are there more items? */ + hasPreviousPage: Scalars['Boolean']['output']; + /** When paginating backwards, the cursor to continue. */ + startCursor?: Maybe; +}; + +export type PartialSettingsType = Settings & { + __typename?: 'PartialSettingsType'; + autoDownloadNewChapters?: Maybe; + backupInterval?: Maybe; + backupPath?: Maybe; + backupTTL?: Maybe; + backupTime?: Maybe; + basicAuthEnabled?: Maybe; + basicAuthPassword?: Maybe; + basicAuthUsername?: Maybe; + debugLogsEnabled?: Maybe; + downloadAsCbz?: Maybe; + downloadsPath?: Maybe; + electronPath?: Maybe; + excludeCompleted?: Maybe; + excludeNotStarted?: Maybe; + excludeUnreadChapters?: Maybe; + globalUpdateInterval?: Maybe; + initialOpenInBrowserEnabled?: Maybe; + ip?: Maybe; + localSourcePath?: Maybe; + maxSourcesInParallel?: Maybe; + port?: Maybe; + socksProxyEnabled?: Maybe; + socksProxyHost?: Maybe; + socksProxyPort?: Maybe; + systemTrayEnabled?: Maybe; + webUIChannel?: Maybe; + webUIFlavor?: Maybe; + webUIInterface?: Maybe; + webUIUpdateCheckInterval?: Maybe; +}; + +export type PartialSettingsTypeInput = { + autoDownloadNewChapters?: InputMaybe; + backupInterval?: InputMaybe; + backupPath?: InputMaybe; + backupTTL?: InputMaybe; + backupTime?: InputMaybe; + basicAuthEnabled?: InputMaybe; + basicAuthPassword?: InputMaybe; + basicAuthUsername?: InputMaybe; + debugLogsEnabled?: InputMaybe; + downloadAsCbz?: InputMaybe; + downloadsPath?: InputMaybe; + electronPath?: InputMaybe; + excludeCompleted?: InputMaybe; + excludeNotStarted?: InputMaybe; + excludeUnreadChapters?: InputMaybe; + globalUpdateInterval?: InputMaybe; + initialOpenInBrowserEnabled?: InputMaybe; + ip?: InputMaybe; + localSourcePath?: InputMaybe; + maxSourcesInParallel?: InputMaybe; + port?: InputMaybe; + socksProxyEnabled?: InputMaybe; + socksProxyHost?: InputMaybe; + socksProxyPort?: InputMaybe; + systemTrayEnabled?: InputMaybe; + webUIChannel?: InputMaybe; + webUIFlavor?: InputMaybe; + webUIInterface?: InputMaybe; + webUIUpdateCheckInterval?: InputMaybe; +}; + +export type Preference = CheckBoxPreference | EditTextPreference | ListPreference | MultiSelectListPreference | SwitchPreference; + +export type Query = { + __typename?: 'Query'; + about: AboutPayload; + categories: CategoryNodeList; + category: CategoryType; + chapter: ChapterType; + chapters: ChapterNodeList; + checkForServerUpdates: Array; + checkForWebUIUpdate: WebUiUpdateInfo; + downloadStatus: DownloadStatus; + extension: ExtensionType; + extensions: ExtensionNodeList; + getWebUIUpdateStatus: WebUiUpdateStatus; + lastUpdateTimestamp: LastUpdateTimestampPayload; + manga: MangaType; + mangas: MangaNodeList; + meta: GlobalMetaType; + metas: GlobalMetaNodeList; + restoreStatus: BackupRestoreStatus; + settings: SettingsType; + source: SourceType; + sources: SourceNodeList; + updateStatus: UpdateStatus; + validateBackup: ValidateBackupResult; +}; + + +export type QueryCategoriesArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QueryCategoryArgs = { + id: Scalars['Int']['input']; +}; + + +export type QueryChapterArgs = { + id: Scalars['Int']['input']; +}; + + +export type QueryChaptersArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QueryExtensionArgs = { + pkgName: Scalars['String']['input']; +}; + + +export type QueryExtensionsArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QueryMangaArgs = { + id: Scalars['Int']['input']; +}; + + +export type QueryMangasArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QueryMetaArgs = { + key: Scalars['String']['input']; +}; + + +export type QueryMetasArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QuerySourceArgs = { + id: Scalars['LongString']['input']; +}; + + +export type QuerySourcesArgs = { + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}; + + +export type QueryValidateBackupArgs = { + input: ValidateBackupInput; +}; + +export type ReorderChapterDownloadInput = { + chapterId: Scalars['Int']['input']; + clientMutationId?: InputMaybe; + to: Scalars['Int']['input']; +}; + +export type ReorderChapterDownloadPayload = { + __typename?: 'ReorderChapterDownloadPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type ResetSettingsInput = { + clientMutationId?: InputMaybe; +}; + +export type ResetSettingsPayload = { + __typename?: 'ResetSettingsPayload'; + clientMutationId?: Maybe; + settings: SettingsType; +}; + +export type RestoreBackupInput = { + backup: Scalars['Upload']['input']; + clientMutationId?: InputMaybe; +}; + +export type RestoreBackupPayload = { + __typename?: 'RestoreBackupPayload'; + clientMutationId?: Maybe; + status: BackupRestoreStatus; +}; + +export type SelectFilter = { + __typename?: 'SelectFilter'; + default: Scalars['Int']['output']; + name: Scalars['String']['output']; + values: Array; +}; + +export type SeparatorFilter = { + __typename?: 'SeparatorFilter'; + name: Scalars['String']['output']; +}; + +export type SetCategoryMetaInput = { + clientMutationId?: InputMaybe; + meta: CategoryMetaTypeInput; +}; + +export type SetCategoryMetaPayload = { + __typename?: 'SetCategoryMetaPayload'; + clientMutationId?: Maybe; + meta: CategoryMetaType; +}; + +export type SetChapterMetaInput = { + clientMutationId?: InputMaybe; + meta: ChapterMetaTypeInput; +}; + +export type SetChapterMetaPayload = { + __typename?: 'SetChapterMetaPayload'; + clientMutationId?: Maybe; + meta: ChapterMetaType; +}; + +export type SetGlobalMetaInput = { + clientMutationId?: InputMaybe; + meta: GlobalMetaTypeInput; +}; + +export type SetGlobalMetaPayload = { + __typename?: 'SetGlobalMetaPayload'; + clientMutationId?: Maybe; + meta: GlobalMetaType; +}; + +export type SetMangaMetaInput = { + clientMutationId?: InputMaybe; + meta: MangaMetaTypeInput; +}; + +export type SetMangaMetaPayload = { + __typename?: 'SetMangaMetaPayload'; + clientMutationId?: Maybe; + meta: MangaMetaType; +}; + +export type SetSettingsInput = { + clientMutationId?: InputMaybe; + settings: PartialSettingsTypeInput; +}; + +export type SetSettingsPayload = { + __typename?: 'SetSettingsPayload'; + clientMutationId?: Maybe; + settings: SettingsType; +}; + +export type Settings = { + autoDownloadNewChapters?: Maybe; + backupInterval?: Maybe; + backupPath?: Maybe; + backupTTL?: Maybe; + backupTime?: Maybe; + basicAuthEnabled?: Maybe; + basicAuthPassword?: Maybe; + basicAuthUsername?: Maybe; + debugLogsEnabled?: Maybe; + downloadAsCbz?: Maybe; + downloadsPath?: Maybe; + electronPath?: Maybe; + excludeCompleted?: Maybe; + excludeNotStarted?: Maybe; + excludeUnreadChapters?: Maybe; + globalUpdateInterval?: Maybe; + initialOpenInBrowserEnabled?: Maybe; + ip?: Maybe; + localSourcePath?: Maybe; + maxSourcesInParallel?: Maybe; + port?: Maybe; + socksProxyEnabled?: Maybe; + socksProxyHost?: Maybe; + socksProxyPort?: Maybe; + systemTrayEnabled?: Maybe; + webUIChannel?: Maybe; + webUIFlavor?: Maybe; + webUIInterface?: Maybe; + webUIUpdateCheckInterval?: Maybe; +}; + +export type SettingsType = Settings & { + __typename?: 'SettingsType'; + autoDownloadNewChapters: Scalars['Boolean']['output']; + backupInterval: Scalars['Int']['output']; + backupPath: Scalars['String']['output']; + backupTTL: Scalars['Int']['output']; + backupTime: Scalars['String']['output']; + basicAuthEnabled: Scalars['Boolean']['output']; + basicAuthPassword: Scalars['String']['output']; + basicAuthUsername: Scalars['String']['output']; + debugLogsEnabled: Scalars['Boolean']['output']; + downloadAsCbz: Scalars['Boolean']['output']; + downloadsPath: Scalars['String']['output']; + electronPath: Scalars['String']['output']; + excludeCompleted: Scalars['Boolean']['output']; + excludeNotStarted: Scalars['Boolean']['output']; + excludeUnreadChapters: Scalars['Boolean']['output']; + globalUpdateInterval: Scalars['Float']['output']; + initialOpenInBrowserEnabled: Scalars['Boolean']['output']; + ip: Scalars['String']['output']; + localSourcePath: Scalars['String']['output']; + maxSourcesInParallel: Scalars['Int']['output']; + port: Scalars['Int']['output']; + socksProxyEnabled: Scalars['Boolean']['output']; + socksProxyHost: Scalars['String']['output']; + socksProxyPort: Scalars['String']['output']; + systemTrayEnabled: Scalars['Boolean']['output']; + webUIChannel: WebUiChannel; + webUIFlavor: WebUiFlavor; + webUIInterface: WebUiInterface; + webUIUpdateCheckInterval: Scalars['Float']['output']; +}; + +export type SortFilter = { + __typename?: 'SortFilter'; + default?: Maybe; + name: Scalars['String']['output']; + values: Array; +}; + +export enum SortOrder { + Asc = 'ASC', + AscNullsFirst = 'ASC_NULLS_FIRST', + AscNullsLast = 'ASC_NULLS_LAST', + Desc = 'DESC', + DescNullsFirst = 'DESC_NULLS_FIRST', + DescNullsLast = 'DESC_NULLS_LAST' +} + +export type SortSelection = { + __typename?: 'SortSelection'; + ascending: Scalars['Boolean']['output']; + index: Scalars['Int']['output']; +}; + +export type SortSelectionInput = { + ascending: Scalars['Boolean']['input']; + index: Scalars['Int']['input']; +}; + +export type SourceConditionInput = { + id?: InputMaybe; + isNsfw?: InputMaybe; + lang?: InputMaybe; + name?: InputMaybe; +}; + +export type SourceEdge = Edge & { + __typename?: 'SourceEdge'; + cursor: Scalars['Cursor']['output']; + node: SourceType; +}; + +export type SourceFilterInput = { + and?: InputMaybe>; + id?: InputMaybe; + isNsfw?: InputMaybe; + lang?: InputMaybe; + name?: InputMaybe; + not?: InputMaybe; + or?: InputMaybe>; +}; + +export type SourceNodeList = NodeList & { + __typename?: 'SourceNodeList'; + edges: Array; + nodes: Array; + pageInfo: PageInfo; + totalCount: Scalars['Int']['output']; +}; + +export enum SourceOrderBy { + Id = 'ID', + Lang = 'LANG', + Name = 'NAME' +} + +export type SourcePreferenceChangeInput = { + checkBoxState?: InputMaybe; + editTextState?: InputMaybe; + listState?: InputMaybe; + multiSelectState?: InputMaybe>; + position: Scalars['Int']['input']; + switchState?: InputMaybe; +}; + +export type SourceType = { + __typename?: 'SourceType'; + displayName: Scalars['String']['output']; + extension: ExtensionType; + filters: Array; + iconUrl: Scalars['String']['output']; + id: Scalars['LongString']['output']; + isConfigurable: Scalars['Boolean']['output']; + isNsfw: Scalars['Boolean']['output']; + lang: Scalars['String']['output']; + manga: MangaNodeList; + name: Scalars['String']['output']; + preferences: Array; + supportsLatest: Scalars['Boolean']['output']; +}; + +export type StartDownloaderInput = { + clientMutationId?: InputMaybe; +}; + +export type StartDownloaderPayload = { + __typename?: 'StartDownloaderPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type StopDownloaderInput = { + clientMutationId?: InputMaybe; +}; + +export type StopDownloaderPayload = { + __typename?: 'StopDownloaderPayload'; + clientMutationId?: Maybe; + downloadStatus: DownloadStatus; +}; + +export type StringFilterInput = { + distinctFrom?: InputMaybe; + distinctFromInsensitive?: InputMaybe; + endsWith?: InputMaybe; + endsWithInsensitive?: InputMaybe; + equalTo?: InputMaybe; + greaterThan?: InputMaybe; + greaterThanInsensitive?: InputMaybe; + greaterThanOrEqualTo?: InputMaybe; + greaterThanOrEqualToInsensitive?: InputMaybe; + in?: InputMaybe>; + inInsensitive?: InputMaybe>; + includes?: InputMaybe; + includesInsensitive?: InputMaybe; + isNull?: InputMaybe; + lessThan?: InputMaybe; + lessThanInsensitive?: InputMaybe; + lessThanOrEqualTo?: InputMaybe; + lessThanOrEqualToInsensitive?: InputMaybe; + like?: InputMaybe; + likeInsensitive?: InputMaybe; + notDistinctFrom?: InputMaybe; + notDistinctFromInsensitive?: InputMaybe; + notEndsWith?: InputMaybe; + notEndsWithInsensitive?: InputMaybe; + notEqualTo?: InputMaybe; + notIn?: InputMaybe>; + notInInsensitive?: InputMaybe>; + notIncludes?: InputMaybe; + notIncludesInsensitive?: InputMaybe; + notLike?: InputMaybe; + notLikeInsensitive?: InputMaybe; + notStartsWith?: InputMaybe; + notStartsWithInsensitive?: InputMaybe; + startsWith?: InputMaybe; + startsWithInsensitive?: InputMaybe; +}; + +export type Subscription = { + __typename?: 'Subscription'; + downloadChanged: DownloadStatus; + updateStatusChanged: UpdateStatus; + webUIUpdateStatusChange: WebUiUpdateStatus; +}; + +export type SwitchPreference = { + __typename?: 'SwitchPreference'; + currentValue?: Maybe; + default: Scalars['Boolean']['output']; + key: Scalars['String']['output']; + summary?: Maybe; + title: Scalars['String']['output']; + visible: Scalars['Boolean']['output']; +}; + +export type TextFilter = { + __typename?: 'TextFilter'; + default: Scalars['String']['output']; + name: Scalars['String']['output']; +}; + +export enum TriState { + Exclude = 'EXCLUDE', + Ignore = 'IGNORE', + Include = 'INCLUDE' +} + +export type TriStateFilter = { + __typename?: 'TriStateFilter'; + default: TriState; + name: Scalars['String']['output']; +}; + +export type UpdateCategoriesInput = { + clientMutationId?: InputMaybe; + ids: Array; + patch: UpdateCategoryPatchInput; +}; + +export type UpdateCategoriesPayload = { + __typename?: 'UpdateCategoriesPayload'; + categories: Array; + clientMutationId?: Maybe; +}; + +export type UpdateCategoryInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; + patch: UpdateCategoryPatchInput; +}; + +export type UpdateCategoryMangaInput = { + categories: Array; + clientMutationId?: InputMaybe; +}; + +export type UpdateCategoryMangaPayload = { + __typename?: 'UpdateCategoryMangaPayload'; + clientMutationId?: Maybe; + updateStatus: UpdateStatus; +}; + +export type UpdateCategoryOrderInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; + position: Scalars['Int']['input']; +}; + +export type UpdateCategoryOrderPayload = { + __typename?: 'UpdateCategoryOrderPayload'; + categories: Array; + clientMutationId?: Maybe; +}; + +export type UpdateCategoryPatchInput = { + default?: InputMaybe; + includeInUpdate?: InputMaybe; + name?: InputMaybe; +}; + +export type UpdateCategoryPayload = { + __typename?: 'UpdateCategoryPayload'; + category: CategoryType; + clientMutationId?: Maybe; +}; + +export type UpdateChapterInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; + patch: UpdateChapterPatchInput; +}; + +export type UpdateChapterPatchInput = { + isBookmarked?: InputMaybe; + isRead?: InputMaybe; + lastPageRead?: InputMaybe; +}; + +export type UpdateChapterPayload = { + __typename?: 'UpdateChapterPayload'; + chapter: ChapterType; + clientMutationId?: Maybe; +}; + +export type UpdateChaptersInput = { + clientMutationId?: InputMaybe; + ids: Array; + patch: UpdateChapterPatchInput; +}; + +export type UpdateChaptersPayload = { + __typename?: 'UpdateChaptersPayload'; + chapters: Array; + clientMutationId?: Maybe; +}; + +export type UpdateExtensionInput = { + clientMutationId?: InputMaybe; + id: Scalars['String']['input']; + patch: UpdateExtensionPatchInput; +}; + +export type UpdateExtensionPatchInput = { + install?: InputMaybe; + uninstall?: InputMaybe; + update?: InputMaybe; +}; + +export type UpdateExtensionPayload = { + __typename?: 'UpdateExtensionPayload'; + clientMutationId?: Maybe; + extension: ExtensionType; +}; + +export type UpdateExtensionsInput = { + clientMutationId?: InputMaybe; + ids: Array; + patch: UpdateExtensionPatchInput; +}; + +export type UpdateExtensionsPayload = { + __typename?: 'UpdateExtensionsPayload'; + clientMutationId?: Maybe; + extensions: Array; +}; + +export type UpdateLibraryMangaInput = { + clientMutationId?: InputMaybe; +}; + +export type UpdateLibraryMangaPayload = { + __typename?: 'UpdateLibraryMangaPayload'; + clientMutationId?: Maybe; + updateStatus: UpdateStatus; +}; + +export type UpdateMangaCategoriesInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; + patch: UpdateMangaCategoriesPatchInput; +}; + +export type UpdateMangaCategoriesPatchInput = { + addToCategories?: InputMaybe>; + clearCategories?: InputMaybe; + removeFromCategories?: InputMaybe>; +}; + +export type UpdateMangaCategoriesPayload = { + __typename?: 'UpdateMangaCategoriesPayload'; + clientMutationId?: Maybe; + manga: MangaType; +}; + +export type UpdateMangaInput = { + clientMutationId?: InputMaybe; + id: Scalars['Int']['input']; + patch: UpdateMangaPatchInput; +}; + +export type UpdateMangaPatchInput = { + inLibrary?: InputMaybe; +}; + +export type UpdateMangaPayload = { + __typename?: 'UpdateMangaPayload'; + clientMutationId?: Maybe; + manga: MangaType; +}; + +export type UpdateMangasCategoriesInput = { + clientMutationId?: InputMaybe; + ids: Array; + patch: UpdateMangaCategoriesPatchInput; +}; + +export type UpdateMangasCategoriesPayload = { + __typename?: 'UpdateMangasCategoriesPayload'; + clientMutationId?: Maybe; + mangas: Array; +}; + +export type UpdateMangasInput = { + clientMutationId?: InputMaybe; + ids: Array; + patch: UpdateMangaPatchInput; +}; + +export type UpdateMangasPayload = { + __typename?: 'UpdateMangasPayload'; + clientMutationId?: Maybe; + mangas: Array; +}; + +export type UpdateSourcePreferenceInput = { + change: SourcePreferenceChangeInput; + clientMutationId?: InputMaybe; + source: Scalars['LongString']['input']; +}; + +export type UpdateSourcePreferencePayload = { + __typename?: 'UpdateSourcePreferencePayload'; + clientMutationId?: Maybe; + preferences: Array; + source: SourceType; +}; + +export enum UpdateState { + Downloading = 'DOWNLOADING', + Error = 'ERROR', + Finished = 'FINISHED', + Stopped = 'STOPPED' +} + +export type UpdateStatus = { + __typename?: 'UpdateStatus'; + completeJobs: UpdateStatusType; + failedJobs: UpdateStatusType; + isRunning: Scalars['Boolean']['output']; + pendingJobs: UpdateStatusType; + runningJobs: UpdateStatusType; + skippedCategories: UpdateStatusCategoryType; + skippedJobs: UpdateStatusType; + updatingCategories: UpdateStatusCategoryType; +}; + +export type UpdateStatusCategoryType = { + __typename?: 'UpdateStatusCategoryType'; + categories: CategoryNodeList; +}; + +export type UpdateStatusType = { + __typename?: 'UpdateStatusType'; + mangas: MangaNodeList; +}; + +export type UpdateStopInput = { + clientMutationId?: InputMaybe; +}; + +export type UpdateStopPayload = { + __typename?: 'UpdateStopPayload'; + clientMutationId?: Maybe; +}; + +export type ValidateBackupInput = { + backup: Scalars['Upload']['input']; +}; + +export type ValidateBackupResult = { + __typename?: 'ValidateBackupResult'; + missingSources: Array; +}; + +export type ValidateBackupSource = { + __typename?: 'ValidateBackupSource'; + id: Scalars['LongString']['output']; + name: Scalars['String']['output']; +}; + +export enum WebUiChannel { + Bundled = 'BUNDLED', + Preview = 'PREVIEW', + Stable = 'STABLE' +} + +export enum WebUiFlavor { + Custom = 'CUSTOM', + Webui = 'WEBUI' +} + +export enum WebUiInterface { + Browser = 'BROWSER', + Electron = 'ELECTRON' +} + +export type WebUiUpdateInfo = { + __typename?: 'WebUIUpdateInfo'; + channel: Scalars['String']['output']; + tag: Scalars['String']['output']; + updateAvailable: Scalars['Boolean']['output']; +}; + +export type WebUiUpdateInput = { + clientMutationId?: InputMaybe; +}; + +export type WebUiUpdatePayload = { + __typename?: 'WebUIUpdatePayload'; + clientMutationId?: Maybe; + updateStatus: WebUiUpdateStatus; +}; + +export type WebUiUpdateStatus = { + __typename?: 'WebUIUpdateStatus'; + info: WebUiUpdateInfo; + progress: Scalars['Int']['output']; + state: UpdateState; +}; + +export type PageInfoFragment = { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null }; + +export type GlobalMetadataFragment = { __typename?: 'GlobalMetaType', key: string, value: string }; + +export type FullCategoryFieldsFragment = { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }; + +export type PartialSourceFieldsFragment = { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean }; + +export type FullSourceFieldsFragment = { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean, preferences: Array<{ __typename?: 'CheckBoxPreference', summary?: string | null, key: string, type: 'CheckBoxPreference', CheckBoxCheckBoxCurrentValue?: boolean | null, CheckBoxDefault: boolean, CheckBoxTitle: string } | { __typename?: 'EditTextPreference', text?: string | null, summary?: string | null, key: string, dialogTitle?: string | null, dialogMessage?: string | null, type: 'EditTextPreference', EditTextPreferenceCurrentValue?: string | null, EditTextPreferenceDefault?: string | null, EditTextPreferenceTitle?: string | null } | { __typename?: 'ListPreference', summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'ListPreference', ListPreferenceCurrentValue?: string | null, ListPreferenceDefault?: string | null, ListPreferenceTitle?: string | null } | { __typename?: 'MultiSelectListPreference', dialogMessage?: string | null, dialogTitle?: string | null, summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'MultiSelectListPreference', MultiSelectListPreferenceTitle?: string | null, MultiSelectListPreferenceDefault?: Array | null, MultiSelectListPreferenceCurrentValue?: Array | null } | { __typename?: 'SwitchPreference', summary?: string | null, key: string, type: 'SwitchPreference', SwitchPreferenceCurrentValue?: boolean | null, SwitchPreferenceDefault: boolean, SwitchPreferenceTitle: string }>, filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter', name: string, type: 'GroupFilter', filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter' } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', name: string, values: Array, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', name: string, values: Array, type: 'SortFilter', SorSortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', values: Array, name: string, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', values: Array, name: string, type: 'SortFilter', SortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> }; + +export type BaseMangaFieldsFragment = { __typename?: 'MangaType', artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }; + +export type PartialMangaFieldsFragment = { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }; + +export type FullChapterFieldsFragment = { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }; + +export type FullMangaFieldsFragment = { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }; + +export type FullExtensionFieldsFragment = { __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string }; + +export type FullDownloadStatusFragment = { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> }; + +export type PartialUpdaterStatusFragment = { __typename?: 'UpdateStatus', isRunning: boolean }; + +export type FullUpdaterStatusFragment = { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, skippedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, updatingCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }, skippedCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } } }; + +export type WebuiUpdateInfoFragment = { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean }; + +export type WebuiUpdateStatusFragment = { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } }; + +export type ServerSettingsFragment = { __typename?: 'SettingsType', autoDownloadNewChapters: boolean, backupInterval: number, backupPath: string, backupTTL: number, backupTime: string, basicAuthEnabled: boolean, basicAuthPassword: string, basicAuthUsername: string, debugLogsEnabled: boolean, downloadAsCbz: boolean, downloadsPath: string, electronPath: string, excludeCompleted: boolean, excludeNotStarted: boolean, excludeUnreadChapters: boolean, globalUpdateInterval: number, initialOpenInBrowserEnabled: boolean, ip: string, localSourcePath: string, maxSourcesInParallel: number, port: number, socksProxyEnabled: boolean, socksProxyHost: string, socksProxyPort: string, systemTrayEnabled: boolean, webUIChannel: WebUiChannel, webUIFlavor: WebUiFlavor, webUIInterface: WebUiInterface, webUIUpdateCheckInterval: number }; + +export type CreateBackupMutationVariables = Exact<{ + input: CreateBackupInput; +}>; + + +export type CreateBackupMutation = { __typename?: 'Mutation', createBackup: { __typename?: 'CreateBackupPayload', clientMutationId?: string | null, url: string } }; + +export type RestoreBackupMutationVariables = Exact<{ + input: RestoreBackupInput; +}>; + + +export type RestoreBackupMutation = { __typename?: 'Mutation', restoreBackup: { __typename?: 'RestoreBackupPayload', clientMutationId?: string | null, status: { __typename?: 'BackupRestoreStatus', mangaProgress: number, state: BackupRestoreState, totalManga: number } } }; + +export type CreateCategoryMutationVariables = Exact<{ + input: CreateCategoryInput; +}>; + + +export type CreateCategoryMutation = { __typename?: 'Mutation', createCategory: { __typename?: 'CreateCategoryPayload', clientMutationId?: string | null, category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } } }; + +export type DeleteCategoryMutationVariables = Exact<{ + input: DeleteCategoryInput; +}>; + + +export type DeleteCategoryMutation = { __typename?: 'Mutation', deleteCategory: { __typename?: 'DeleteCategoryPayload', clientMutationId?: string | null, category?: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } | null } }; + +export type DeleteCategoryMetadataMutationVariables = Exact<{ + input: DeleteCategoryMetaInput; +}>; + + +export type DeleteCategoryMetadataMutation = { __typename?: 'Mutation', deleteCategoryMeta: { __typename?: 'DeleteCategoryMetaPayload', clientMutationId?: string | null, meta?: { __typename?: 'CategoryMetaType', key: string, value: string, category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } } | null, category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } } }; + +export type SetCategoryMetadataMutationVariables = Exact<{ + input: SetCategoryMetaInput; +}>; + + +export type SetCategoryMetadataMutation = { __typename?: 'Mutation', setCategoryMeta: { __typename?: 'SetCategoryMetaPayload', clientMutationId?: string | null, meta: { __typename?: 'CategoryMetaType', key: string, value: string, category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } } } }; + +export type UpdateCategoryMutationVariables = Exact<{ + input: UpdateCategoryInput; +}>; + + +export type UpdateCategoryMutation = { __typename?: 'Mutation', updateCategory: { __typename?: 'UpdateCategoryPayload', clientMutationId?: string | null, category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } } }; + +export type UpdateCategoriesMutationVariables = Exact<{ + input: UpdateCategoriesInput; +}>; + + +export type UpdateCategoriesMutation = { __typename?: 'Mutation', updateCategories: { __typename?: 'UpdateCategoriesPayload', clientMutationId?: string | null, categories: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }; + +export type UpdateCategoryOrderMutationVariables = Exact<{ + input: UpdateCategoryOrderInput; +}>; + + +export type UpdateCategoryOrderMutation = { __typename?: 'Mutation', updateCategoryOrder: { __typename?: 'UpdateCategoryOrderPayload', clientMutationId?: string | null, categories: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }; + +export type DeleteChapterMetadataMutationVariables = Exact<{ + input: DeleteChapterMetaInput; +}>; + + +export type DeleteChapterMetadataMutation = { __typename?: 'Mutation', deleteChapterMeta: { __typename?: 'DeleteChapterMetaPayload', clientMutationId?: string | null, meta?: { __typename?: 'ChapterMetaType', key: string, value: string, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } | null, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } }; + +export type GetChapterPagesFetchMutationVariables = Exact<{ + input: FetchChapterPagesInput; +}>; + + +export type GetChapterPagesFetchMutation = { __typename?: 'Mutation', fetchChapterPages: { __typename?: 'FetchChapterPagesPayload', clientMutationId?: string | null, pages: Array, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } }; + +export type GetMangaChaptersFetchMutationVariables = Exact<{ + input: FetchChaptersInput; +}>; + + +export type GetMangaChaptersFetchMutation = { __typename?: 'Mutation', fetchChapters: { __typename?: 'FetchChaptersPayload', clientMutationId?: string | null, chapters: Array<{ __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }> } }; + +export type SetChapterMetadataMutationVariables = Exact<{ + input: SetChapterMetaInput; +}>; + + +export type SetChapterMetadataMutation = { __typename?: 'Mutation', setChapterMeta: { __typename?: 'SetChapterMetaPayload', clientMutationId?: string | null, meta: { __typename?: 'ChapterMetaType', key: string, value: string, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } } }; + +export type UpdateChapterMutationVariables = Exact<{ + input: UpdateChapterInput; +}>; + + +export type UpdateChapterMutation = { __typename?: 'Mutation', updateChapter: { __typename?: 'UpdateChapterPayload', clientMutationId?: string | null, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } }; + +export type UpdateChaptersMutationVariables = Exact<{ + input: UpdateChaptersInput; +}>; + + +export type UpdateChaptersMutation = { __typename?: 'Mutation', updateChapters: { __typename?: 'UpdateChaptersPayload', clientMutationId?: string | null, chapters: Array<{ __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }> } }; + +export type ClearDownloaderMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type ClearDownloaderMutation = { __typename?: 'Mutation', clearDownloader: { __typename?: 'ClearDownloaderPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type DeleteDownloadedChapterMutationVariables = Exact<{ + input: DeleteDownloadedChapterInput; +}>; + + +export type DeleteDownloadedChapterMutation = { __typename?: 'Mutation', deleteDownloadedChapter: { __typename?: 'DeleteDownloadedChapterPayload', clientMutationId?: string | null, chapters: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } } }; + +export type DeleteDownloadedChaptersMutationVariables = Exact<{ + input: DeleteDownloadedChaptersInput; +}>; + + +export type DeleteDownloadedChaptersMutation = { __typename?: 'Mutation', deleteDownloadedChapters: { __typename?: 'DeleteDownloadedChaptersPayload', clientMutationId?: string | null, chapters: Array<{ __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }> } }; + +export type DequeueChapterDownloadMutationVariables = Exact<{ + input: DequeueChapterDownloadInput; +}>; + + +export type DequeueChapterDownloadMutation = { __typename?: 'Mutation', dequeueChapterDownload: { __typename?: 'DequeueChapterDownloadPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type DequeueChapterDownloadsMutationVariables = Exact<{ + input: DequeueChapterDownloadsInput; +}>; + + +export type DequeueChapterDownloadsMutation = { __typename?: 'Mutation', dequeueChapterDownloads: { __typename?: 'DequeueChapterDownloadsPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type EnqueueChapterDownloadMutationVariables = Exact<{ + input: EnqueueChapterDownloadInput; +}>; + + +export type EnqueueChapterDownloadMutation = { __typename?: 'Mutation', enqueueChapterDownload: { __typename?: 'EnqueueChapterDownloadPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type EnqueueChapterDownloadsMutationVariables = Exact<{ + input: EnqueueChapterDownloadsInput; +}>; + + +export type EnqueueChapterDownloadsMutation = { __typename?: 'Mutation', enqueueChapterDownloads: { __typename?: 'EnqueueChapterDownloadsPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type ReorderChapterDownloadMutationVariables = Exact<{ + input: ReorderChapterDownloadInput; +}>; + + +export type ReorderChapterDownloadMutation = { __typename?: 'Mutation', reorderChapterDownload: { __typename?: 'ReorderChapterDownloadPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type StartDownloaderMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type StartDownloaderMutation = { __typename?: 'Mutation', startDownloader: { __typename?: 'StartDownloaderPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type StopDownloaderMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type StopDownloaderMutation = { __typename?: 'Mutation', stopDownloader: { __typename?: 'StopDownloaderPayload', clientMutationId?: string | null, downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } } }; + +export type GetExtensionsFetchMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type GetExtensionsFetchMutation = { __typename?: 'Mutation', fetchExtensions: { __typename?: 'FetchExtensionsPayload', clientMutationId?: string | null, extensions: Array<{ __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string }> } }; + +export type UpdateExtensionMutationVariables = Exact<{ + input: UpdateExtensionInput; +}>; + + +export type UpdateExtensionMutation = { __typename?: 'Mutation', updateExtension: { __typename?: 'UpdateExtensionPayload', clientMutationId?: string | null, extension: { __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string } } }; + +export type UpdateExtensionsMutationVariables = Exact<{ + input: UpdateExtensionsInput; +}>; + + +export type UpdateExtensionsMutation = { __typename?: 'Mutation', updateExtensions: { __typename?: 'UpdateExtensionsPayload', clientMutationId?: string | null, extensions: Array<{ __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string }> } }; + +export type InstallExternalExtensionMutationVariables = Exact<{ + file: Scalars['Upload']['input']; +}>; + + +export type InstallExternalExtensionMutation = { __typename?: 'Mutation', installExternalExtension: { __typename?: 'InstallExternalExtensionPayload', clientMutationId?: string | null, extension: { __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string } } }; + +export type DeleteGlobalMetadataMutationVariables = Exact<{ + input: DeleteGlobalMetaInput; +}>; + + +export type DeleteGlobalMetadataMutation = { __typename?: 'Mutation', deleteGlobalMeta: { __typename?: 'DeleteGlobalMetaPayload', clientMutationId?: string | null, meta?: { __typename?: 'GlobalMetaType', key: string, value: string } | null } }; + +export type SetGlobalMetadataMutationVariables = Exact<{ + input: SetGlobalMetaInput; +}>; + + +export type SetGlobalMetadataMutation = { __typename?: 'Mutation', setGlobalMeta: { __typename?: 'SetGlobalMetaPayload', clientMutationId?: string | null, meta: { __typename?: 'GlobalMetaType', key: string, value: string } } }; + +export type DeleteMangaMetadataMutationVariables = Exact<{ + input: DeleteMangaMetaInput; +}>; + + +export type DeleteMangaMetadataMutation = { __typename?: 'Mutation', deleteMangaMeta: { __typename?: 'DeleteMangaMetaPayload', clientMutationId?: string | null, meta?: { __typename?: 'MangaMetaType', key: string, value: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } | null, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } }; + +export type GetMangaFetchMutationVariables = Exact<{ + input: FetchMangaInput; +}>; + + +export type GetMangaFetchMutation = { __typename?: 'Mutation', fetchManga: { __typename?: 'FetchMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } }; + +export type SetMangaMetadataMutationVariables = Exact<{ + input: SetMangaMetaInput; +}>; + + +export type SetMangaMetadataMutation = { __typename?: 'Mutation', setMangaMeta: { __typename?: 'SetMangaMetaPayload', clientMutationId?: string | null, meta: { __typename?: 'MangaMetaType', key: string, value: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } } }; + +export type UpdateMangaMutationVariables = Exact<{ + input: UpdateMangaInput; +}>; + + +export type UpdateMangaMutation = { __typename?: 'Mutation', updateManga: { __typename?: 'UpdateMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } }; + +export type UpdateMangaCategoriesMutationVariables = Exact<{ + input: UpdateMangaCategoriesInput; +}>; + + +export type UpdateMangaCategoriesMutation = { __typename?: 'Mutation', updateMangaCategories: { __typename?: 'UpdateMangaCategoriesPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } } }; + +export type UpdateMangasMutationVariables = Exact<{ + input: UpdateMangasInput; +}>; + + +export type UpdateMangasMutation = { __typename?: 'Mutation', updateMangas: { __typename?: 'UpdateMangasPayload', clientMutationId?: string | null, mangas: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }; + +export type UpdateMangasCategoriesMutationVariables = Exact<{ + input: UpdateMangasCategoriesInput; +}>; + + +export type UpdateMangasCategoriesMutation = { __typename?: 'Mutation', updateMangasCategories: { __typename?: 'UpdateMangasCategoriesPayload', clientMutationId?: string | null, mangas: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }; + +export type UpdateWebuiMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type UpdateWebuiMutation = { __typename?: 'Mutation', updateWebUI: { __typename?: 'WebUIUpdatePayload', clientMutationId?: string | null, updateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } } }; + +export type ResetServerSettingsMutationVariables = Exact<{ + input: ResetSettingsInput; +}>; + + +export type ResetServerSettingsMutation = { __typename?: 'Mutation', resetSettings: { __typename?: 'ResetSettingsPayload', clientMutationId?: string | null, settings: { __typename?: 'SettingsType', autoDownloadNewChapters: boolean, backupInterval: number, backupPath: string, backupTTL: number, backupTime: string, basicAuthEnabled: boolean, basicAuthPassword: string, basicAuthUsername: string, debugLogsEnabled: boolean, downloadAsCbz: boolean, downloadsPath: string, electronPath: string, excludeCompleted: boolean, excludeNotStarted: boolean, excludeUnreadChapters: boolean, globalUpdateInterval: number, initialOpenInBrowserEnabled: boolean, ip: string, localSourcePath: string, maxSourcesInParallel: number, port: number, socksProxyEnabled: boolean, socksProxyHost: string, socksProxyPort: string, systemTrayEnabled: boolean, webUIChannel: WebUiChannel, webUIFlavor: WebUiFlavor, webUIInterface: WebUiInterface, webUIUpdateCheckInterval: number } } }; + +export type UpdateServerSettingsMutationVariables = Exact<{ + input: SetSettingsInput; +}>; + + +export type UpdateServerSettingsMutation = { __typename?: 'Mutation', setSettings: { __typename?: 'SetSettingsPayload', clientMutationId?: string | null, settings: { __typename?: 'SettingsType', autoDownloadNewChapters: boolean, backupInterval: number, backupPath: string, backupTTL: number, backupTime: string, basicAuthEnabled: boolean, basicAuthPassword: string, basicAuthUsername: string, debugLogsEnabled: boolean, downloadAsCbz: boolean, downloadsPath: string, electronPath: string, excludeCompleted: boolean, excludeNotStarted: boolean, excludeUnreadChapters: boolean, globalUpdateInterval: number, initialOpenInBrowserEnabled: boolean, ip: string, localSourcePath: string, maxSourcesInParallel: number, port: number, socksProxyEnabled: boolean, socksProxyHost: string, socksProxyPort: string, systemTrayEnabled: boolean, webUIChannel: WebUiChannel, webUIFlavor: WebUiFlavor, webUIInterface: WebUiInterface, webUIUpdateCheckInterval: number } } }; + +export type GetSourceMangasFetchMutationVariables = Exact<{ + input: FetchSourceMangaInput; +}>; + + +export type GetSourceMangasFetchMutation = { __typename?: 'Mutation', fetchSourceManga: { __typename?: 'FetchSourceMangaPayload', clientMutationId?: string | null, hasNextPage: boolean, mangas: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }; + +export type UpdateSourcePreferencesMutationVariables = Exact<{ + input: UpdateSourcePreferenceInput; +}>; + + +export type UpdateSourcePreferencesMutation = { __typename?: 'Mutation', updateSourcePreference: { __typename?: 'UpdateSourcePreferencePayload', clientMutationId?: string | null, source: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean, preferences: Array<{ __typename?: 'CheckBoxPreference', summary?: string | null, key: string, type: 'CheckBoxPreference', CheckBoxCheckBoxCurrentValue?: boolean | null, CheckBoxDefault: boolean, CheckBoxTitle: string } | { __typename?: 'EditTextPreference', text?: string | null, summary?: string | null, key: string, dialogTitle?: string | null, dialogMessage?: string | null, type: 'EditTextPreference', EditTextPreferenceCurrentValue?: string | null, EditTextPreferenceDefault?: string | null, EditTextPreferenceTitle?: string | null } | { __typename?: 'ListPreference', summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'ListPreference', ListPreferenceCurrentValue?: string | null, ListPreferenceDefault?: string | null, ListPreferenceTitle?: string | null } | { __typename?: 'MultiSelectListPreference', dialogMessage?: string | null, dialogTitle?: string | null, summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'MultiSelectListPreference', MultiSelectListPreferenceTitle?: string | null, MultiSelectListPreferenceDefault?: Array | null, MultiSelectListPreferenceCurrentValue?: Array | null } | { __typename?: 'SwitchPreference', summary?: string | null, key: string, type: 'SwitchPreference', SwitchPreferenceCurrentValue?: boolean | null, SwitchPreferenceDefault: boolean, SwitchPreferenceTitle: string }>, filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter', name: string, type: 'GroupFilter', filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter' } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', name: string, values: Array, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', name: string, values: Array, type: 'SortFilter', SorSortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', values: Array, name: string, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', values: Array, name: string, type: 'SortFilter', SortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> } } }; + +export type UpdateCategoryMangasMutationVariables = Exact<{ + input: UpdateCategoryMangaInput; +}>; + + +export type UpdateCategoryMangasMutation = { __typename?: 'Mutation', updateCategoryManga: { __typename?: 'UpdateCategoryMangaPayload', clientMutationId?: string | null, updateStatus: { __typename?: 'UpdateStatus', isRunning: boolean } } }; + +export type UpdateLibraryMangasMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type UpdateLibraryMangasMutation = { __typename?: 'Mutation', updateLibraryManga: { __typename?: 'UpdateLibraryMangaPayload', clientMutationId?: string | null, updateStatus: { __typename?: 'UpdateStatus', isRunning: boolean } } }; + +export type StopUpdaterMutationVariables = Exact<{ + input?: InputMaybe; +}>; + + +export type StopUpdaterMutation = { __typename?: 'Mutation', updateStop: { __typename?: 'UpdateStopPayload', clientMutationId?: string | null } }; + +export type ValidateBackupQueryVariables = Exact<{ + input: ValidateBackupInput; +}>; + + +export type ValidateBackupQuery = { __typename?: 'Query', validateBackup: { __typename?: 'ValidateBackupResult', missingSources: Array<{ __typename?: 'ValidateBackupSource', id: any, name: string }> } }; + +export type GetRestoreStatusQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetRestoreStatusQuery = { __typename?: 'Query', restoreStatus: { __typename?: 'BackupRestoreStatus', mangaProgress: number, state: BackupRestoreState, totalManga: number } }; + +export type GetCategoriesQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetCategoriesQuery = { __typename?: 'Query', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } }; + +export type GetCategoryQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetCategoryQuery = { __typename?: 'Query', category: { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } } }; + +export type GetCategoryMangasQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetCategoryMangasQuery = { __typename?: 'Query', category: { __typename?: 'CategoryType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } } }; + +export type GetChapterQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetChapterQuery = { __typename?: 'Query', chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }; + +export type GetChaptersQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetChaptersQuery = { __typename?: 'Query', chapters: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } }; + +export type GetDownloadStatusQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetDownloadStatusQuery = { __typename?: 'Query', downloadStatus: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } }; + +export type GetExtensionQueryVariables = Exact<{ + pkgName: Scalars['String']['input']; +}>; + + +export type GetExtensionQuery = { __typename?: 'Query', extension: { __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string } }; + +export type GetExtensionsQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetExtensionsQuery = { __typename?: 'Query', extensions: { __typename?: 'ExtensionNodeList', totalCount: number, nodes: Array<{ __typename?: 'ExtensionType', apkName: string, hasUpdate: boolean, iconUrl: string, isInstalled: boolean, isNsfw: boolean, isObsolete: boolean, lang: string, name: string, pkgName: string, versionCode: number, versionName: string }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } }; + +export type GetGlobalMetadataQueryVariables = Exact<{ + key: Scalars['String']['input']; +}>; + + +export type GetGlobalMetadataQuery = { __typename?: 'Query', meta: { __typename?: 'GlobalMetaType', key: string, value: string } }; + +export type GetGlobalMetadatasQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetGlobalMetadatasQuery = { __typename?: 'Query', metas: { __typename?: 'GlobalMetaNodeList', totalCount: number, nodes: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } }; + +export type GetMangaQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetMangaQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null } }; + +export type GetMangasQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetMangasQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: any | null } } }; + +export type GetAboutQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetAboutQuery = { __typename?: 'Query', about: { __typename?: 'AboutPayload', buildTime: any, buildType: string, discord: string, github: string, name: string, revision: string, version: string } }; + +export type CheckForServerUpdatesQueryVariables = Exact<{ [key: string]: never; }>; + + +export type CheckForServerUpdatesQuery = { __typename?: 'Query', checkForServerUpdates: Array<{ __typename?: 'CheckForServerUpdatesPayload', channel: string, tag: string, url: string }> }; + +export type CheckForWebuiUpdateQueryVariables = Exact<{ [key: string]: never; }>; + + +export type CheckForWebuiUpdateQuery = { __typename?: 'Query', checkForWebUIUpdate: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } }; + +export type GetWebuiUpdateStatusQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetWebuiUpdateStatusQuery = { __typename?: 'Query', getWebUIUpdateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } }; + +export type GetServerSettingsQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetServerSettingsQuery = { __typename?: 'Query', settings: { __typename?: 'SettingsType', autoDownloadNewChapters: boolean, backupInterval: number, backupPath: string, backupTTL: number, backupTime: string, basicAuthEnabled: boolean, basicAuthPassword: string, basicAuthUsername: string, debugLogsEnabled: boolean, downloadAsCbz: boolean, downloadsPath: string, electronPath: string, excludeCompleted: boolean, excludeNotStarted: boolean, excludeUnreadChapters: boolean, globalUpdateInterval: number, initialOpenInBrowserEnabled: boolean, ip: string, localSourcePath: string, maxSourcesInParallel: number, port: number, socksProxyEnabled: boolean, socksProxyHost: string, socksProxyPort: string, systemTrayEnabled: boolean, webUIChannel: WebUiChannel, webUIFlavor: WebUiFlavor, webUIInterface: WebUiInterface, webUIUpdateCheckInterval: number } }; + +export type GetSourceQueryVariables = Exact<{ + id: Scalars['LongString']['input']; +}>; + + +export type GetSourceQuery = { __typename?: 'Query', source: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean, preferences: Array<{ __typename?: 'CheckBoxPreference', summary?: string | null, key: string, type: 'CheckBoxPreference', CheckBoxCheckBoxCurrentValue?: boolean | null, CheckBoxDefault: boolean, CheckBoxTitle: string } | { __typename?: 'EditTextPreference', text?: string | null, summary?: string | null, key: string, dialogTitle?: string | null, dialogMessage?: string | null, type: 'EditTextPreference', EditTextPreferenceCurrentValue?: string | null, EditTextPreferenceDefault?: string | null, EditTextPreferenceTitle?: string | null } | { __typename?: 'ListPreference', summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'ListPreference', ListPreferenceCurrentValue?: string | null, ListPreferenceDefault?: string | null, ListPreferenceTitle?: string | null } | { __typename?: 'MultiSelectListPreference', dialogMessage?: string | null, dialogTitle?: string | null, summary?: string | null, key: string, entryValues: Array, entries: Array, type: 'MultiSelectListPreference', MultiSelectListPreferenceTitle?: string | null, MultiSelectListPreferenceDefault?: Array | null, MultiSelectListPreferenceCurrentValue?: Array | null } | { __typename?: 'SwitchPreference', summary?: string | null, key: string, type: 'SwitchPreference', SwitchPreferenceCurrentValue?: boolean | null, SwitchPreferenceDefault: boolean, SwitchPreferenceTitle: string }>, filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter', name: string, type: 'GroupFilter', filters: Array<{ __typename?: 'CheckBoxFilter', name: string, type: 'CheckBoxFilter', CheckBoxFilterDefault: boolean } | { __typename?: 'GroupFilter' } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', name: string, values: Array, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', name: string, values: Array, type: 'SortFilter', SorSortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> } | { __typename?: 'HeaderFilter', name: string, type: 'HeaderFilter' } | { __typename?: 'SelectFilter', values: Array, name: string, type: 'SelectFilter', SelectFilterDefault: number } | { __typename?: 'SeparatorFilter', name: string, type: 'SeparatorFilter' } | { __typename?: 'SortFilter', values: Array, name: string, type: 'SortFilter', SortFilterDefault?: { __typename?: 'SortSelection', ascending: boolean, index: number } | null } | { __typename?: 'TextFilter', name: string, type: 'TextFilter', TextFilterDefault: string } | { __typename?: 'TriStateFilter', name: string, type: 'TriStateFilter', TriStateFilterDefault: TriState }> } }; + +export type GetSourcesQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetSourcesQuery = { __typename?: 'Query', sources: { __typename?: 'SourceNodeList', nodes: Array<{ __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean }> } }; + +export type GetUpdateStatusQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetUpdateStatusQuery = { __typename?: 'Query', updateStatus: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, skippedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, updatingCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }, skippedCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } } } }; + +export type GetLastUpdateTimestampQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetLastUpdateTimestampQuery = { __typename?: 'Query', lastUpdateTimestamp: { __typename?: 'LastUpdateTimestampPayload', timestamp: any } }; + +export type DownloadStatusSubscriptionVariables = Exact<{ [key: string]: never; }>; + + +export type DownloadStatusSubscription = { __typename?: 'Subscription', downloadChanged: { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } }> } }; + +export type WebuiUpdateSubscriptionVariables = Exact<{ [key: string]: never; }>; + + +export type WebuiUpdateSubscription = { __typename?: 'Subscription', webUIUpdateStatusChange: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } }; + +export type UpdaterSubscriptionVariables = Exact<{ [key: string]: never; }>; + + +export type UpdaterSubscription = { __typename?: 'Subscription', updateStatusChanged: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, skippedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: any, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: any, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: any, url: string, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, updatingCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }, skippedCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeInUpdate, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } } } }; From 1c794c24b5e9cc02d9998945091e9cf1783c84a6 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:33:16 +0200 Subject: [PATCH 07/47] Setup intellij "GraphQL" plugin --- .gitignore | 4 +++- src/lib/graphql/graphql.config.yml | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/lib/graphql/graphql.config.yml diff --git a/.gitignore b/.gitignore index 82e9a202..fde0f2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ node_modules/ build/* -tools/scripts/github_token.json \ No newline at end of file +tools/scripts/github_token.json + +src/lib/graphql/schema.json diff --git a/src/lib/graphql/graphql.config.yml b/src/lib/graphql/graphql.config.yml new file mode 100644 index 00000000..0c80f0d1 --- /dev/null +++ b/src/lib/graphql/graphql.config.yml @@ -0,0 +1,7 @@ +schema: schema.json # download the schema from the server and place it in "src/lib/graphql/" +documents: [ + 'src/lib/graphql/queries/**', + 'src/lib/graphql/mutations/**', + 'src/lib/graphql/subscriptions/**', + 'src/lib/graphql/Fragments.ts', +] \ No newline at end of file From bffc1669e211fb9b7a082fa5661bb40bdc59a53b Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 15 Aug 2023 13:54:29 +0200 Subject: [PATCH 08/47] Move "RequestManager" in sub folder --- src/components/ExtensionCard.tsx | 2 +- src/components/MangaCard.tsx | 2 +- src/components/SourceCard.tsx | 2 +- src/components/library/UpdateChecker.tsx | 2 +- src/components/library/useSubscription.ts | 2 +- src/components/manga/ChapterCard.tsx | 2 +- src/components/manga/ChapterList.tsx | 2 +- src/components/manga/MangaDetails.tsx | 2 +- src/components/manga/hooks.ts | 2 +- src/components/navbar/action/CategorySelect.tsx | 2 +- src/lib/{ => requests}/RequestManager.ts | 6 +++--- src/screens/DownloadQueue.tsx | 2 +- src/screens/Extensions.tsx | 2 +- src/screens/Library.tsx | 2 +- src/screens/Manga.tsx | 2 +- src/screens/Reader.tsx | 2 +- src/screens/SearchAll.tsx | 2 +- src/screens/Settings.tsx | 2 +- src/screens/SourceConfigure.tsx | 2 +- src/screens/SourceMangas.tsx | 2 +- src/screens/Sources.tsx | 2 +- src/screens/Updates.tsx | 2 +- src/screens/settings/About.tsx | 2 +- src/screens/settings/Backup.tsx | 2 +- src/screens/settings/Categories.tsx | 2 +- src/screens/settings/LibrarySettings.tsx | 2 +- src/util/metadata.ts | 2 +- src/util/readerSettings.ts | 2 +- src/util/searchSettings.ts | 2 +- 29 files changed, 31 insertions(+), 31 deletions(-) rename src/lib/{ => requests}/RequestManager.ts (99%) diff --git a/src/components/ExtensionCard.tsx b/src/components/ExtensionCard.tsx index d386d82e..bfbf5f7e 100644 --- a/src/components/ExtensionCard.tsx +++ b/src/components/ExtensionCard.tsx @@ -15,7 +15,7 @@ import Typography from '@mui/material/Typography'; import { Box } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { IExtension, TranslationKey } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; interface IProps { extension: IExtension; diff --git a/src/components/MangaCard.tsx b/src/components/MangaCard.tsx index 15c9d45f..892b1751 100644 --- a/src/components/MangaCard.tsx +++ b/src/components/MangaCard.tsx @@ -13,7 +13,7 @@ import { Link } from 'react-router-dom'; import { Avatar, Box, CardContent, styled } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { IMangaCard } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { GridLayout, useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import SpinnerImage from '@/components/util/SpinnerImage'; diff --git a/src/components/SourceCard.tsx b/src/components/SourceCard.tsx index 9b0c9561..d779de44 100644 --- a/src/components/SourceCard.tsx +++ b/src/components/SourceCard.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { ISource } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { translateExtensionLanguage } from '@/screens/util/Extensions'; import { SourceContentType } from '@/screens/SourceMangas'; diff --git a/src/components/library/UpdateChecker.tsx b/src/components/library/UpdateChecker.tsx index dada41fe..b03b8842 100644 --- a/src/components/library/UpdateChecker.tsx +++ b/src/components/library/UpdateChecker.tsx @@ -14,7 +14,7 @@ import { Box } from '@mui/material'; import Typography from '@mui/material/Typography'; import { useTranslation } from 'react-i18next'; import { IUpdateStatus } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; interface IProgressProps { diff --git a/src/components/library/useSubscription.ts b/src/components/library/useSubscription.ts index 5c21f1dd..0ddc3a63 100644 --- a/src/components/library/useSubscription.ts +++ b/src/components/library/useSubscription.ts @@ -7,7 +7,7 @@ */ import { useEffect, useState } from 'react'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; const useSubscription = (path: string, callback?: (newValue: T) => boolean | void) => { const [state, setState] = useState(); diff --git a/src/components/manga/ChapterCard.tsx b/src/components/manga/ChapterCard.tsx index e6e492c4..072c3caf 100644 --- a/src/components/manga/ChapterCard.tsx +++ b/src/components/manga/ChapterCard.tsx @@ -28,7 +28,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { IChapter, IDownloadChapter } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { getUploadDateString } from '@/util/date'; import DownloadStateIndicator from '@/components/molecules/DownloadStateIndicator'; diff --git a/src/components/manga/ChapterList.tsx b/src/components/manga/ChapterList.tsx index 1514bcce..1d76f5a5 100644 --- a/src/components/manga/ChapterList.tsx +++ b/src/components/manga/ChapterList.tsx @@ -12,7 +12,7 @@ import React, { ComponentProps, useEffect, useMemo, useRef, useState } from 'rea import { Virtuoso } from 'react-virtuoso'; import { useTranslation } from 'react-i18next'; import { BatchChaptersChange, IChapter, IDownloadChapter, IQueue, TranslationKey } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import useSubscription from '@/components/library/useSubscription'; import ChapterCard from '@/components/manga/ChapterCard'; import ResumeFab from '@/components/manga/ResumeFAB'; diff --git a/src/components/manga/MangaDetails.tsx b/src/components/manga/MangaDetails.tsx index 85767253..4fa4a125 100644 --- a/src/components/manga/MangaDetails.tsx +++ b/src/components/manga/MangaDetails.tsx @@ -16,7 +16,7 @@ import { mutate } from 'swr'; import { t as translate } from 'i18next'; import Button from '@mui/material/Button'; import { IManga, ISource } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; const DetailsWrapper = styled('div')(({ theme }) => ({ diff --git a/src/components/manga/hooks.ts b/src/components/manga/hooks.ts index 0edbefb0..2bc45b70 100644 --- a/src/components/manga/hooks.ts +++ b/src/components/manga/hooks.ts @@ -8,7 +8,7 @@ import { useCallback, useEffect, useState } from 'react'; import { mutate } from 'swr'; -import requestManager, { RequestManager } from '@/lib/RequestManager'; +import requestManager, { RequestManager } from '@/lib/requests/RequestManager.ts'; export const useRefreshManga = (mangaId: string) => { const [fetchingOnline, setFetchingOnline] = useState(false); diff --git a/src/components/navbar/action/CategorySelect.tsx b/src/components/navbar/action/CategorySelect.tsx index 3a56f8af..218e58a6 100644 --- a/src/components/navbar/action/CategorySelect.tsx +++ b/src/components/navbar/action/CategorySelect.tsx @@ -16,7 +16,7 @@ import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import FormGroup from '@mui/material/FormGroup'; import { useTranslation } from 'react-i18next'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; interface IProps { open: boolean; diff --git a/src/lib/RequestManager.ts b/src/lib/requests/RequestManager.ts similarity index 99% rename from src/lib/RequestManager.ts rename to src/lib/requests/RequestManager.ts index 8a2e34e2..ec62ae01 100644 --- a/src/lib/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -28,9 +28,9 @@ import { SourcePreferences, SourceSearchResult, UpdateCheck, -} from '@/typings'; -import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/RestClient'; -import storage from '@/util/localStorage'; +} from '@/typings.ts'; +import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/RestClient.ts'; +import storage from '@/util/localStorage.tsx'; enum SWRHttpMethod { SWR_GET, diff --git a/src/screens/DownloadQueue.tsx b/src/screens/DownloadQueue.tsx index ea76fab4..adbb469f 100644 --- a/src/screens/DownloadQueue.tsx +++ b/src/screens/DownloadQueue.tsx @@ -19,7 +19,7 @@ import Typography from '@mui/material/Typography'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { IChapter, IQueue } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import StrictModeDroppable from '@/lib/StrictModeDroppable'; import makeToast from '@/components/util/Toast'; import { NavbarToolbar } from '@/components/navbar/DefaultNavBar'; diff --git a/src/screens/Extensions.tsx b/src/screens/Extensions.tsx index 62ef028e..e0dddc81 100644 --- a/src/screens/Extensions.tsx +++ b/src/screens/Extensions.tsx @@ -15,7 +15,7 @@ import { Virtuoso } from 'react-virtuoso'; import { Typography, useMediaQuery, useTheme } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { IExtension } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { extensionDefaultLangs, DefaultLanguage, langSortCmp } from '@/util/language'; import useLocalStorage from '@/util/useLocalStorage'; import { diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index b0539cec..b6722da2 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -10,7 +10,7 @@ import { Chip, Tab, Tabs, styled, Box } from '@mui/material'; import React, { useContext, useEffect, useMemo, useState } from 'react'; import { useQueryParam, NumberParam } from 'use-query-params'; import { useTranslation } from 'react-i18next'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import NavbarContext from '@/components/context/NavbarContext'; import EmptyView from '@/components/util/EmptyView'; import LoadingPlaceholder from '@/components/util/LoadingPlaceholder'; diff --git a/src/screens/Manga.tsx b/src/screens/Manga.tsx index 3660c23c..af6b0e58 100644 --- a/src/screens/Manga.tsx +++ b/src/screens/Manga.tsx @@ -11,7 +11,7 @@ import { CircularProgress, IconButton, Stack, Tooltip, Box } from '@mui/material import React, { useContext, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; import ChapterList from '@/components/manga/ChapterList'; import { useRefreshManga } from '@/components/manga/hooks'; diff --git a/src/screens/Reader.tsx b/src/screens/Reader.tsx index 4d19b798..ac2489f5 100644 --- a/src/screens/Reader.tsx +++ b/src/screens/Reader.tsx @@ -12,7 +12,7 @@ import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { Box } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { ChapterOffset, IChapter, IManga, IMangaCard, IReaderSettings, ReaderType, TranslationKey } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { checkAndHandleMissingStoredReaderSettings, getReaderSettingsFor, diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index 7f88c988..78f27d3a 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -12,7 +12,7 @@ import { Link } from 'react-router-dom'; import { StringParam, useQueryParam } from 'use-query-params'; import { useTranslation } from 'react-i18next'; import { ISource } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import useLocalStorage from '@/util/useLocalStorage'; import { langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from '@/util/language'; import { translateExtensionLanguage } from '@/screens/util/Extensions'; diff --git a/src/screens/Settings.tsx b/src/screens/Settings.tsx index d38bcb00..8cc66045 100644 --- a/src/screens/Settings.tsx +++ b/src/screens/Settings.tsx @@ -35,7 +35,7 @@ import ViewModuleIcon from '@mui/icons-material/ViewModule'; import { useTranslation } from 'react-i18next'; import LanguageIcon from '@mui/icons-material/Language'; import CollectionsOutlinedBookmarkIcon from '@mui/icons-material/CollectionsBookmarkOutlined'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { langCodeToName } from '@/util/language'; import useLocalStorage from '@/util/useLocalStorage'; import ListItemLink from '@/components/util/ListItemLink'; diff --git a/src/screens/SourceConfigure.tsx b/src/screens/SourceConfigure.tsx index 0b761c66..9fc74c3d 100644 --- a/src/screens/SourceConfigure.tsx +++ b/src/screens/SourceConfigure.tsx @@ -10,7 +10,7 @@ import { createElement, useContext, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import List from '@mui/material/List'; import { useTranslation } from 'react-i18next'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import cloneObject from '@/util/cloneObject'; import NavbarContext from '@/components/context/NavbarContext'; import { SwitchPreferenceCompat, CheckBoxPreference } from '@/components/sourceConfiguration/TwoStatePreference'; diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index 8f932627..187a0df1 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -18,7 +18,7 @@ import FavoriteIcon from '@mui/icons-material/Favorite'; import NewReleasesIcon from '@mui/icons-material/NewReleases'; import FilterListIcon from '@mui/icons-material/FilterList'; import { IManga, PaginatedMangaList, TranslationKey } from '@/typings'; -import requestManager, { AbortableSWRInfiniteResponse } from '@/lib/RequestManager'; +import requestManager, { AbortableSWRInfiniteResponse } from '@/lib/requests/RequestManager.ts'; import { useDebounce } from '@/components/manga/hooks'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import SourceGridLayout from '@/components/source/GridLayouts'; diff --git a/src/screens/Sources.tsx b/src/screens/Sources.tsx index 52ed46e0..1143a10a 100644 --- a/src/screens/Sources.tsx +++ b/src/screens/Sources.tsx @@ -12,7 +12,7 @@ import TravelExploreIcon from '@mui/icons-material/TravelExplore'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { ISource } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import useLocalStorage from '@/util/useLocalStorage'; import { sourceDefualtLangs, sourceForcedDefaultLangs, langSortCmp } from '@/util/language'; import { translateExtensionLanguage } from '@/screens/util/Extensions'; diff --git a/src/screens/Updates.tsx b/src/screens/Updates.tsx index fcbb5853..85e13d84 100644 --- a/src/screens/Updates.tsx +++ b/src/screens/Updates.tsx @@ -19,7 +19,7 @@ import { useTranslation } from 'react-i18next'; import { t as translate } from 'i18next'; import { GroupedVirtuoso } from 'react-virtuoso'; import { IChapter, IMangaChapter, IQueue } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import LoadingPlaceholder from '@/components/util/LoadingPlaceholder'; import EmptyView from '@/components/util/EmptyView'; import DownloadStateIndicator from '@/components/molecules/DownloadStateIndicator'; diff --git a/src/screens/settings/About.tsx b/src/screens/settings/About.tsx index db196541..28c74b22 100644 --- a/src/screens/settings/About.tsx +++ b/src/screens/settings/About.tsx @@ -11,7 +11,7 @@ import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import { useTranslation } from 'react-i18next'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import ListItemLink from '@/components/util/ListItemLink'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; import LoadingPlaceholder from '@/components/util/LoadingPlaceholder'; diff --git a/src/screens/settings/Backup.tsx b/src/screens/settings/Backup.tsx index c4755594..d6171b01 100644 --- a/src/screens/settings/Backup.tsx +++ b/src/screens/settings/Backup.tsx @@ -12,7 +12,7 @@ import ListItemText from '@mui/material/ListItemText'; import { fromEvent } from 'file-selector'; import { useTranslation } from 'react-i18next'; import { ListItemButton } from '@mui/material'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; import ListItemLink from '@/components/util/ListItemLink'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; diff --git a/src/screens/settings/Categories.tsx b/src/screens/settings/Categories.tsx index 5c0dd991..938bfec3 100644 --- a/src/screens/settings/Categories.tsx +++ b/src/screens/settings/Categories.tsx @@ -25,7 +25,7 @@ import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import { useTranslation } from 'react-i18next'; import { ICategory } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import StrictModeDroppable from '@/lib/StrictModeDroppable'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; diff --git a/src/screens/settings/LibrarySettings.tsx b/src/screens/settings/LibrarySettings.tsx index b6740fae..e690ced7 100644 --- a/src/screens/settings/LibrarySettings.tsx +++ b/src/screens/settings/LibrarySettings.tsx @@ -21,7 +21,7 @@ import { styled } from '@mui/material'; import { t as translate } from 'i18next'; import { useTranslation } from 'react-i18next'; import { ICategory, IncludeInGlobalUpdate } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; import ThreeStateCheckboxInput from '@/components/atoms/ThreeStateCheckboxInput'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; diff --git a/src/util/metadata.ts b/src/util/metadata.ts index 32b0ca94..8811056b 100644 --- a/src/util/metadata.ts +++ b/src/util/metadata.ts @@ -19,7 +19,7 @@ import { MetadataHolder, MetadataKeyValuePair, } from '@/typings'; -import requestManager, { RequestManager } from '@/lib/RequestManager'; +import requestManager, { RequestManager } from '@/lib/requests/RequestManager.ts'; const APP_METADATA_KEY_PREFIX = 'webUI_'; diff --git a/src/util/readerSettings.ts b/src/util/readerSettings.ts index b595181e..a732e6f7 100644 --- a/src/util/readerSettings.ts +++ b/src/util/readerSettings.ts @@ -7,7 +7,7 @@ */ import { IManga, Metadata, MetadataHolder, IReaderSettings, MetadataKeyValuePair } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { getMetadataFrom, requestUpdateMangaMetadata, requestUpdateServerMetadata } from '@/util/metadata'; type UndefinedReaderSettings = { diff --git a/src/util/searchSettings.ts b/src/util/searchSettings.ts index 417ebc87..dc082368 100644 --- a/src/util/searchSettings.ts +++ b/src/util/searchSettings.ts @@ -7,7 +7,7 @@ */ import { Metadata, ISearchSettings } from '@/typings'; -import requestManager from '@/lib/RequestManager'; +import requestManager from '@/lib/requests/RequestManager.ts'; import { getMetadataFrom } from '@/util/metadata'; export const getDefaultSettings = (): ISearchSettings => ({ From a0b686497f7b408ede50354f62541272caf0835b Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 15 Aug 2023 13:54:55 +0200 Subject: [PATCH 09/47] Move "RestClient" in sub folder --- src/lib/requests/RequestManager.ts | 2 +- src/lib/{ => requests/client}/RestClient.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/lib/{ => requests/client}/RestClient.ts (98%) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index ec62ae01..a6d18410 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -29,7 +29,7 @@ import { SourceSearchResult, UpdateCheck, } from '@/typings.ts'; -import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/RestClient.ts'; +import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; enum SWRHttpMethod { diff --git a/src/lib/RestClient.ts b/src/lib/requests/client/RestClient.ts similarity index 98% rename from src/lib/RestClient.ts rename to src/lib/requests/client/RestClient.ts index d4ff8d69..ea6b2512 100644 --- a/src/lib/RestClient.ts +++ b/src/lib/requests/client/RestClient.ts @@ -7,7 +7,7 @@ */ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import storage from '@/util/localStorage'; +import storage from '@/util/localStorage.tsx'; export enum HttpMethod { GET = 'get', From 0ee47c872b781e8f80c385f668bb982fd3244e85 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 15 Aug 2023 14:39:45 +0200 Subject: [PATCH 10/47] Introduce "BaseClient" --- .eslintrc.js | 2 ++ src/lib/requests/client/BaseClient.ts | 32 +++++++++++++++++++++++++++ src/lib/requests/client/RestClient.ts | 21 ++++++------------ 3 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 src/lib/requests/client/BaseClient.ts diff --git a/.eslintrc.js b/.eslintrc.js index 8399a281..49093f35 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,6 +27,8 @@ module.exports = { 'prettier/prettier': 'error', + 'class-methods-use-this': 'off', + 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], // just why diff --git a/src/lib/requests/client/BaseClient.ts b/src/lib/requests/client/BaseClient.ts new file mode 100644 index 00000000..8fee7e3f --- /dev/null +++ b/src/lib/requests/client/BaseClient.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import storage from '@/util/localStorage.tsx'; + +// eslint-disable-next-line import/prefer-default-export +export abstract class BaseClient { + protected client!: Client; + + public abstract readonly fetcher: Fetcher; + + constructor() { + this.createClient(); + } + + public getBaseUrl(): string { + const { hostname, port, protocol } = window.location; + + // if port is 3000 it's probably running from webpack development server + const inferredPort = port === '3000' ? '4567' : port; + return storage.getItem('serverBaseURL', `${protocol}//${hostname}:${inferredPort}`); + } + + protected abstract createClient(): void; + + public abstract updateConfig(config: Partial): void; +} diff --git a/src/lib/requests/client/RestClient.ts b/src/lib/requests/client/RestClient.ts index ea6b2512..a21adef1 100644 --- a/src/lib/requests/client/RestClient.ts +++ b/src/lib/requests/client/RestClient.ts @@ -7,7 +7,7 @@ */ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; -import storage from '@/util/localStorage.tsx'; +import { BaseClient } from '@/lib/requests/client/BaseClient.ts'; export enum HttpMethod { GET = 'get', @@ -28,13 +28,10 @@ export interface IRestClient { patch>(url: string, data?: any): Promise; } -export class RestClient implements IRestClient { - protected client!: AxiosInstance; - - constructor() { - this.createClient(); - } - +export class RestClient + extends BaseClient(url: string, data: any) => Promise> + implements IRestClient +{ public readonly fetcher = async ( url: string, { @@ -75,12 +72,8 @@ export class RestClient implements IRestClient { return result.data; }; - private createClient(): void { - const { hostname, port, protocol } = window.location; - - // if port is 3000 it's probably running from webpack development server - const inferredPort = port === '3000' ? '4567' : port; - const baseURL = storage.getItem('serverBaseURL', `${protocol}//${hostname}:${inferredPort}`); + protected override createClient(): void { + const baseURL = this.getBaseUrl(); this.client = axios.create({ // baseURL must not have trailing slash From 181eb6c811d2a149b7680935a6968abd73264c68 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:21:59 +0200 Subject: [PATCH 11/47] Add graphql logic to RequestManager --- src/lib/requests/RequestManager.ts | 126 +++++++++++++++++++++++ src/lib/requests/client/GraphQLClient.ts | 53 ++++++++++ 2 files changed, 179 insertions(+) create mode 100644 src/lib/requests/client/GraphQLClient.ts diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index a6d18410..6a03ee5e 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -9,6 +9,18 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios'; import useSWR, { Middleware, SWRConfiguration, SWRResponse } from 'swr'; import useSWRInfinite, { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite'; +import { + FetchResult, + MutationHookOptions, + MutationOptions, + MutationTuple, + QueryHookOptions, + QueryResult, + TypedDocumentNode, + useMutation, + useQuery, +} from '@apollo/client'; +import { OperationVariables } from '@apollo/client/core'; import { BackupValidationResult, BatchChaptersChange, @@ -31,6 +43,7 @@ import { } from '@/typings.ts'; import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; +import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; enum SWRHttpMethod { SWR_GET, @@ -39,6 +52,12 @@ enum SWRHttpMethod { SWR_POST_INFINITE, } +enum GQLMethod { + USE_QUERY = 'USE_QUERY', + USE_MUTATION = 'USE_MUTATION', + MUTATION = 'MUTATION', +} + type HttpMethodType = DefaultHttpMethod | SWRHttpMethod; const HttpMethod = { ...SWRHttpMethod, ...DefaultHttpMethod }; @@ -64,6 +83,16 @@ export type AbortableSWRInfiniteResponse = SWRInfiniteR AbortableRequest & SWRInfiniteResponseLoadInfo; +type AbortableApolloUseQueryResponse< + Data = any, + Variables extends OperationVariables = OperationVariables, +> = QueryResult & AbortableRequest; +type AbortableApolloUseMutationResponse = [ + MutationTuple[0], + MutationTuple[1] & AbortableRequest, +]; +type AbortableApolloMutationResponse = { response: Promise> } & AbortableRequest; + const isLoadingMore = (swrResult: SWRInfiniteResponse): boolean => { const isNextPageMissing = !!swrResult.data && typeof swrResult.data[swrResult.size - 1] === 'undefined'; const isRequestActive = swrResult.isValidating; @@ -97,6 +126,8 @@ const disableSwrCache: Middleware = (useSWRNext) => (key, fetcher, config) => { export class RequestManager { public static readonly API_VERSION = '/api/v1/'; + private readonly graphQLClient = new GraphQLClient(); + private readonly restClient: RestClient = new RestClient(); public getClient(): IRestClient { @@ -105,6 +136,7 @@ export class RequestManager { public updateClient(config: Partial): void { this.restClient.updateConfig(config); + this.graphQLClient.updateConfig({ uri: config.baseURL }); } public getBaseUrl(): string { @@ -138,6 +170,100 @@ export class RequestManager { return `${this.getValidUrlFor(imageUrl, apiVersion)}${useCacheQuery}`; } + private doRequestNew( + method: GQLMethod.USE_QUERY, + operation: TypedDocumentNode, + variables: Variables, + options?: Partial>, + ): AbortableApolloUseQueryResponse; + + private doRequestNew( + method: GQLMethod.USE_MUTATION, + operation: TypedDocumentNode, + variables: Variables | undefined, + options?: Partial>, + ): AbortableApolloUseMutationResponse; + + private doRequestNew( + method: GQLMethod.MUTATION, + operation: TypedDocumentNode, + variables: Variables, + options?: Partial>, + ): AbortableApolloMutationResponse; + + private doRequestNew( + method: GQLMethod, + operation: TypedDocumentNode, + variables: Variables, + options?: + | QueryHookOptions + | MutationHookOptions + | MutationOptions, + ): + | AbortableApolloUseQueryResponse + | AbortableApolloUseMutationResponse + | AbortableApolloMutationResponse { + const abortController = new AbortController(); + const abortRequest = (reason?: any): void => { + if (!abortController.signal.aborted) { + abortController.abort(reason); + } + }; + + switch (method) { + case GQLMethod.USE_QUERY: + return { + ...useQuery(operation, { + variables, + client: this.graphQLClient.client, + ...options, + context: { + ...options?.context, + fetchOptions: { + signal: abortController.signal, + ...options?.context?.fetchOptions, + }, + }, + }), + abortRequest, + }; + case GQLMethod.USE_MUTATION: + // eslint-disable-next-line no-case-declarations + const mutationResult = useMutation(operation, { + variables, + client: this.graphQLClient.client, + ...(options as MutationHookOptions), + context: { + ...options?.context, + fetchOptions: { + signal: abortController.signal, + ...options?.context?.fetchOptions, + }, + }, + }); + + return [mutationResult[0], { ...mutationResult[1], abortRequest }]; + case GQLMethod.MUTATION: + return { + response: this.graphQLClient.client.mutate({ + mutation: operation, + variables, + ...(options as MutationOptions), + context: { + ...options?.context, + fetchOptions: { + signal: abortController.signal, + ...options?.context?.fetchOptions, + }, + }, + }), + abortRequest, + }; + default: + throw new Error(`unexpected GQLRequest type "${method}"`); + } + } + private useSwr< Data = any, ErrorResponse = any, diff --git a/src/lib/requests/client/GraphQLClient.ts b/src/lib/requests/client/GraphQLClient.ts new file mode 100644 index 00000000..6a66a6cd --- /dev/null +++ b/src/lib/requests/client/GraphQLClient.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { ApolloClient, ApolloClientOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client'; +import { createUploadLink } from 'apollo-upload-client'; +import { BaseClient } from '@/lib/requests/client/BaseClient.ts'; +import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts'; + +const typePolicies: StrictTypedTypePolicies = { + GlobalMetaType: { keyFields: ['key'] }, + ExtensionType: { keyFields: ['apkName'] }, + AboutPayload: { keyFields: [] }, +}; + +// eslint-disable-next-line import/prefer-default-export +export class GraphQLClient extends BaseClient< + ApolloClient, + ApolloClientOptions, + null +> { + readonly fetcher = null; + + public declare client: ApolloClient; + + public override getBaseUrl(): string { + return `${super.getBaseUrl()}/api/graphql`; + } + + private createUploadLink() { + return createUploadLink({ uri: () => this.getBaseUrl() }); + } + + private createLink() { + return this.createUploadLink(); + } + + protected createClient() { + this.client = new ApolloClient({ + cache: new InMemoryCache({ + typePolicies, + }), + connectToDevTools: true, + link: this.createLink(), + }); + } + + public override updateConfig() {} +} From b9480736c31e742fbef78182419efcf2e203085d Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sun, 27 Aug 2023 21:39:47 +0200 Subject: [PATCH 12/47] Log apollo errors --- src/App.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index 36b1a176..76130286 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,8 @@ import { Container } from '@mui/material'; import CssBaseline from '@mui/material/CssBaseline'; import React from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; +import { loadErrorMessages, loadDevMessages } from '@apollo/client/dev'; +import { __DEV__ } from '@apollo/client/utilities/globals'; import AppContext from '@/components/context/AppContext'; import Browse from '@/screens/Browse'; import DownloadQueue from '@/screens/DownloadQueue'; @@ -31,6 +33,11 @@ import '@/i18n'; import LibrarySettings from '@/screens/settings/LibrarySettings'; import DefaultNavBar from '@/components/navbar/DefaultNavBar'; +if (__DEV__) { + // Adds messages only in a dev environment + loadDevMessages(); + loadErrorMessages(); +} const App: React.FC = () => ( From 80cb06dfd5ecba58873ef7d029af67571585e188 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:24:40 +0200 Subject: [PATCH 13/47] Use gql for "global metadata" --- src/lib/requests/RequestManager.ts | 24 +++++++++++++++++++----- src/util/metadata.ts | 14 ++++++++++++++ src/util/readerSettings.ts | 14 ++++++++++---- src/util/searchSettings.ts | 9 +++++---- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 6a03ee5e..d4b49919 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -34,7 +34,6 @@ import { ISource, ISourceFilters, IUpdateStatus, - Metadata, PaginatedList, PaginatedMangaList, SourcePreferences, @@ -44,6 +43,14 @@ import { import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; +import { + GetGlobalMetadatasQuery, + GetGlobalMetadatasQueryVariables, + SetGlobalMetadataMutation, + SetGlobalMetadataMutationVariables, +} from '@/lib/graphql/generated/graphql.ts'; +import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; +import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; enum SWRHttpMethod { SWR_GET, @@ -423,12 +430,19 @@ export class RequestManager { } } - public useGetGlobalMeta(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'meta', { swrOptions }); + public useGetGlobalMeta( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_GLOBAL_METADATAS, {}, options); } - public setGlobalMetadata(key: string, value: any): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, 'meta', { formData: { key, value } }); + public setGlobalMetadata(key: string, value: any): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + SET_GLOBAL_METADATA, + { input: { meta: { key, value: `${value}` } } }, + { refetchQueries: [GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS] }, + ); } public useGetAbout(swrOptions?: SWROptions): AbortableSWRResponse { diff --git a/src/util/metadata.ts b/src/util/metadata.ts index 8811056b..acd2233d 100644 --- a/src/util/metadata.ts +++ b/src/util/metadata.ts @@ -20,6 +20,7 @@ import { MetadataKeyValuePair, } from '@/typings'; import requestManager, { RequestManager } from '@/lib/requests/RequestManager.ts'; +import { MetaType } from '@/lib/graphql/generated/graphql.ts'; const APP_METADATA_KEY_PREFIX = 'webUI_'; @@ -362,3 +363,16 @@ export const requestUpdateCategoryMetadata = async ( category: ICategory, keysToValues: MetadataKeyValuePair[], ): Promise => requestUpdateMetadata(category, 'category', keysToValues); + +export const convertGqlMetadata = (gqlMetadata?: MetaType[]): Metadata | undefined => { + if (!gqlMetadata) { + return undefined; + } + + const metadata: Metadata = {}; + gqlMetadata.forEach(({ key, value }) => { + metadata[key] = value; + }); + + return metadata; +}; diff --git a/src/util/readerSettings.ts b/src/util/readerSettings.ts index a732e6f7..9dce9c73 100644 --- a/src/util/readerSettings.ts +++ b/src/util/readerSettings.ts @@ -8,7 +8,12 @@ import { IManga, Metadata, MetadataHolder, IReaderSettings, MetadataKeyValuePair } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; -import { getMetadataFrom, requestUpdateMangaMetadata, requestUpdateServerMetadata } from '@/util/metadata'; +import { + convertGqlMetadata, + getMetadataFrom, + requestUpdateMangaMetadata, + requestUpdateServerMetadata, +} from '@/util/metadata'; type UndefinedReaderSettings = { [setting in keyof IReaderSettings]: IReaderSettings[setting] | undefined; @@ -47,10 +52,11 @@ export const useDefaultReaderSettings = (): { settings: IReaderSettings; loading: boolean; } => { - const { data: meta, isLoading } = requestManager.useGetGlobalMeta(); - const settings = getReaderSettingsWithDefaultValueFallback(meta); + const { data, loading } = requestManager.useGetGlobalMeta(); + const metadata = convertGqlMetadata(data?.metas.nodes); + const settings = getReaderSettingsWithDefaultValueFallback(metadata); - return { metadata: meta, settings, loading: isLoading }; + return { metadata, settings, loading }; }; /** diff --git a/src/util/searchSettings.ts b/src/util/searchSettings.ts index dc082368..18958d81 100644 --- a/src/util/searchSettings.ts +++ b/src/util/searchSettings.ts @@ -8,7 +8,7 @@ import { Metadata, ISearchSettings } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; -import { getMetadataFrom } from '@/util/metadata'; +import { convertGqlMetadata, getMetadataFrom } from '@/util/metadata'; export const getDefaultSettings = (): ISearchSettings => ({ ignoreFilters: false, @@ -24,8 +24,9 @@ export const useSearchSettings = (): { settings: ISearchSettings; loading: boolean; } => { - const { data: meta, isLoading } = requestManager.useGetGlobalMeta(); - const settings = getSearchSettingsWithDefaultValueFallback(meta); + const { data, loading } = requestManager.useGetGlobalMeta(); + const metadata = convertGqlMetadata(data?.metas.nodes); + const settings = getSearchSettingsWithDefaultValueFallback(metadata); - return { metadata: meta, settings, loading: isLoading }; + return { metadata, settings, loading }; }; From 59468bc5685d872600299f5d2f3997230fe57f2c Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:25:46 +0200 Subject: [PATCH 14/47] Use gql for "about" --- src/lib/requests/RequestManager.ts | 10 +++++++--- src/screens/settings/About.tsx | 3 ++- src/typings.ts | 10 ---------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index d4b49919..0a890cc7 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -24,7 +24,6 @@ import { OperationVariables } from '@apollo/client/core'; import { BackupValidationResult, BatchChaptersChange, - IAbout, ICategory, IChapter, IExtension, @@ -44,6 +43,8 @@ import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/ import storage from '@/util/localStorage.tsx'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; import { + GetAboutQuery, + GetAboutQueryVariables, GetGlobalMetadatasQuery, GetGlobalMetadatasQueryVariables, SetGlobalMetadataMutation, @@ -51,6 +52,7 @@ import { } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; +import { GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts'; enum SWRHttpMethod { SWR_GET, @@ -445,8 +447,10 @@ export class RequestManager { ); } - public useGetAbout(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'settings/about', { swrOptions }); + public useGetAbout( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_ABOUT, {}, options); } public useCheckForUpdate(swrOptions?: SWROptions): AbortableSWRResponse { diff --git a/src/screens/settings/About.tsx b/src/screens/settings/About.tsx index 28c74b22..a46289c6 100644 --- a/src/screens/settings/About.tsx +++ b/src/screens/settings/About.tsx @@ -25,7 +25,8 @@ export default function About() { setAction(null); }, [t]); - const { data: about } = requestManager.useGetAbout(); + const { data } = requestManager.useGetAbout(); + const about = data?.about; useSetDefaultBackTo('settings'); diff --git a/src/typings.ts b/src/typings.ts index df8ab19e..d3c227f6 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -253,16 +253,6 @@ export interface IReaderProps { prevChapter: () => void; } -export interface IAbout { - name: string; - version: string; - revision: string; - buildType: 'Stable' | 'Preview'; - buildTime: number; - github: string; - discord: string; -} - export interface IDownloadChapter { chapterIndex: number; mangaId: number; From 81cfeedbba59037998e938ab031f6055f5cbaca6 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:26:06 +0200 Subject: [PATCH 15/47] Use gql for "checkForUpdate" --- src/lib/requests/RequestManager.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 0a890cc7..57c97580 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -37,12 +37,13 @@ import { PaginatedMangaList, SourcePreferences, SourceSearchResult, - UpdateCheck, } from '@/typings.ts'; import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; import { + CheckForServerUpdatesQuery, + CheckForServerUpdatesQueryVariables, GetAboutQuery, GetAboutQueryVariables, GetGlobalMetadatasQuery, @@ -52,7 +53,7 @@ import { } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; -import { GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts'; +import { CHECK_FOR_SERVER_UPDATES, GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts'; enum SWRHttpMethod { SWR_GET, @@ -453,8 +454,10 @@ export class RequestManager { return this.doRequestNew(GQLMethod.USE_QUERY, GET_ABOUT, {}, options); } - public useCheckForUpdate(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'settings/check-update', { swrOptions }); + public useCheckForUpdate( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, CHECK_FOR_SERVER_UPDATES, {}, options); } public useGetExtensionList(swrOptions?: SWROptions): AbortableSWRResponse { From 4a80e18cd0df8e9fc231af46afc8c2d6ddb1d5f6 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:28:23 +0200 Subject: [PATCH 16/47] Use gql for "extensions" --- src/components/ExtensionCard.tsx | 19 +++++------ src/lib/requests/RequestManager.ts | 55 +++++++++++++++++++++++------- src/screens/Extensions.tsx | 39 ++++++++++----------- src/screens/util/Extensions.ts | 10 +++--- src/typings.ts | 15 ++------ 5 files changed, 77 insertions(+), 61 deletions(-) diff --git a/src/components/ExtensionCard.tsx b/src/components/ExtensionCard.tsx index bfbf5f7e..2825f30b 100644 --- a/src/components/ExtensionCard.tsx +++ b/src/components/ExtensionCard.tsx @@ -14,12 +14,11 @@ import Avatar from '@mui/material/Avatar'; import Typography from '@mui/material/Typography'; import { Box } from '@mui/material'; import { useTranslation } from 'react-i18next'; -import { IExtension, TranslationKey } from '@/typings'; +import { Extension, TranslationKey } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; interface IProps { - extension: IExtension; - notifyInstall: () => void; + extension: Extension; } enum ExtensionAction { @@ -65,17 +64,16 @@ export default function ExtensionCard(props: IProps) { const { t } = useTranslation(); const { - extension: { name, lang, versionName, installed, hasUpdate, obsolete, pkgName, iconUrl, isNsfw }, - notifyInstall, + extension: { name, lang, versionName, isInstalled, hasUpdate, isObsolete, pkgName, iconUrl, isNsfw }, } = props; const [installedState, setInstalledState] = useState(() => { - if (obsolete) { + if (isObsolete) { return InstalledState.OBSOLETE; } if (hasUpdate) { return InstalledState.UPDATE; } - return installed ? InstalledState.UNINSTALL : InstalledState.INSTALL; + return isInstalled ? InstalledState.UNINSTALL : InstalledState.INSTALL; }); const langPress = lang === 'all' ? t('extension.language.all') : lang.toUpperCase(); @@ -87,19 +85,18 @@ export default function ExtensionCard(props: IProps) { setInstalledState(state); switch (action) { case ExtensionAction.INSTALL: - await requestManager.installExtension(pkgName).response; + await requestManager.updateExtension(pkgName, { install: true }).response; break; case ExtensionAction.UNINSTALL: - await requestManager.uninstallExtension(pkgName).response; + await requestManager.updateExtension(pkgName, { uninstall: true }).response; break; case ExtensionAction.UPDATE: - await requestManager.updateExtension(pkgName).response; + await requestManager.updateExtension(pkgName, { update: true }).response; break; default: throw new Error(`Unexpected ExtensionAction "${action}"`); } setInstalledState(nextAction); - notifyInstall(); }; function handleButtonClick() { diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 57c97580..84df632c 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -26,7 +26,6 @@ import { BatchChaptersChange, ICategory, IChapter, - IExtension, IManga, IMangaChapter, IncludeInGlobalUpdate, @@ -46,14 +45,29 @@ import { CheckForServerUpdatesQueryVariables, GetAboutQuery, GetAboutQueryVariables, + GetExtensionsFetchMutation, + GetExtensionsFetchMutationVariables, + GetExtensionsQuery, + GetExtensionsQueryVariables, GetGlobalMetadatasQuery, GetGlobalMetadatasQueryVariables, + InstallExternalExtensionMutation, + InstallExternalExtensionMutationVariables, SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, + UpdateExtensionMutation, + UpdateExtensionMutationVariables, + UpdateExtensionPatchInput, } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; import { CHECK_FOR_SERVER_UPDATES, GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts'; +import { GET_EXTENSION, GET_EXTENSIONS } from '@/lib/graphql/queries/ExtensionQuery.ts'; +import { + GET_EXTENSIONS_FETCH, + INSTALL_EXTERNAL_EXTENSION, + UPDATE_EXTENSION, +} from '@/lib/graphql/mutations/ExtensionMutation.ts'; enum SWRHttpMethod { SWR_GET, @@ -460,24 +474,39 @@ export class RequestManager { return this.doRequestNew(GQLMethod.USE_QUERY, CHECK_FOR_SERVER_UPDATES, {}, options); } - public useGetExtensionList(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'extension/list', { swrOptions }); + public useGetExtensionList( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_EXTENSIONS, {}, options); } - public installExtension(extension: string | File): AbortableAxiosResponse { - if (typeof extension === 'string') { - return this.doRequest(HttpMethod.GET, `extension/install/${extension}`); - } - - return this.doRequest(HttpMethod.POST, `extension/install`, { formData: { file: extension } }); + public useExtensionListFetch( + options?: MutationHookOptions, + ): AbortableApolloUseMutationResponse { + return this.doRequestNew(GQLMethod.USE_MUTATION, GET_EXTENSIONS_FETCH, {}, options); } - public updateExtension(extension: string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `extension/update/${extension}`); + public installExternalExtension( + extensionFile: File, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + INSTALL_EXTERNAL_EXTENSION, + { file: extensionFile }, + { refetchQueries: [GET_EXTENSION, GET_EXTENSIONS] }, + ); } - public uninstallExtension(extension: string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `extension/uninstall/${extension}`); + public updateExtension( + id: string, + patch: UpdateExtensionPatchInput, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_EXTENSION, + { input: { id, patch } }, + { refetchQueries: [GET_EXTENSION, GET_EXTENSIONS, GET_SOURCES] }, + ); } public getExtensionIconUrl(extension: string): string { diff --git a/src/screens/Extensions.tsx b/src/screens/Extensions.tsx index e0dddc81..1cd323d4 100644 --- a/src/screens/Extensions.tsx +++ b/src/screens/Extensions.tsx @@ -14,7 +14,6 @@ import { StringParam, useQueryParam } from 'use-query-params'; import { Virtuoso } from 'react-virtuoso'; import { Typography, useMediaQuery, useTheme } from '@mui/material'; import { useTranslation } from 'react-i18next'; -import { IExtension } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { extensionDefaultLangs, DefaultLanguage, langSortCmp } from '@/util/language'; import useLocalStorage from '@/util/useLocalStorage'; @@ -31,11 +30,12 @@ import { makeToaster } from '@/components/util/Toast'; import LangSelect from '@/components/navbar/action/LangSelect'; import NavbarContext from '@/components/context/NavbarContext'; import ExtensionCard from '@/components/ExtensionCard'; +import { Extension } from '@/typings.ts'; const LANGUAGE = 0; const EXTENSIONS = 1; -function getExtensionsInfo(extensions: IExtension[]): { +function getExtensionsInfo(extensions: Extension[]): { allLangs: string[]; groupedExtensions: GroupedExtensionsResult; } { @@ -55,12 +55,12 @@ function getExtensionsInfo(extensions: IExtension[]): { allLangs.push(extension.lang); } } - if (extension.installed) { + if (extension.isInstalled) { if (extension.hasUpdate) { sortedExtensions[ExtensionState.UPDATE_PENDING].push(extension); return; } - if (extension.obsolete) { + if (extension.isObsolete) { sortedExtensions[ExtensionState.OBSOLETE].push(extension); return; } @@ -100,7 +100,17 @@ export default function MangaExtensions() { const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const [query] = useQueryParam('query', StringParam); - const { data: allExtensions, mutate, isLoading } = requestManager.useGetExtensionList(); + const [extensionsTimestamp, setExtensionsTimestamp] = useLocalStorage('extensionsTimestamp', 0); + const [fetchExtensions, { loading: isFetching }] = requestManager.useExtensionListFetch(); + const { data, loading: isLoading } = requestManager.useGetExtensionList(); + const allExtensions = data?.extensions.nodes; + + useEffect(() => { + const updateExtensionsList = Date.now() - extensionsTimestamp >= 1000 * 60; // update list in case it's older than 1 minute + if (updateExtensionsList) { + fetchExtensions().catch(() => setExtensionsTimestamp(Date.now())); + } + }, []); const filteredExtensions = useMemo( () => @@ -122,7 +132,7 @@ export default function MangaExtensions() { [shownLangs, groupedExtensions], ); - const flatRenderItems: (IExtension | string)[] = filteredGroupedExtensions.flat(2); + const flatRenderItems: (Extension | string)[] = filteredGroupedExtensions.flat(2); const [toasts, makeToast] = makeToaster(useState([])); @@ -134,10 +144,9 @@ export default function MangaExtensions() { makeToast(t('extension.label.installing_file'), 'info'); requestManager - .installExtension(file) + .installExternalExtension(file) .response.then(() => { makeToast(t('extension.label.installed_successfully'), 'success'); - mutate(); }) .catch(() => makeToast(t('extension.label.installation_failed'), 'error')); } else { @@ -178,7 +187,7 @@ export default function MangaExtensions() { }; }, []); - if (isLoading) { + if (isLoading || isFetching) { return ; } @@ -220,17 +229,9 @@ export default function MangaExtensions() { ); } - const item = flatRenderItems[index] as IExtension; + const item = flatRenderItems[index] as Extension; - return ( - { - mutate(); - }} - /> - ); + return ; }} /> diff --git a/src/screens/util/Extensions.ts b/src/screens/util/Extensions.ts index 2ed2dcee..09e5d4de 100644 --- a/src/screens/util/Extensions.ts +++ b/src/screens/util/Extensions.ts @@ -7,7 +7,7 @@ */ import { t } from 'i18next'; -import { IExtension, TranslationKey } from '@/typings'; +import { Extension, TranslationKey } from '@/typings'; import { DefaultLanguage, langCodeToName } from '@/util/language'; export enum ExtensionState { @@ -16,16 +16,16 @@ export enum ExtensionState { OBSOLETE = 'OBSOLETE', } -export type GroupedExtensionsResult = [KEY, IExtension[]][]; +export type GroupedExtensionsResult = [KEY, Extension[]][]; export type GroupedByExtensionState = { - [state in ExtensionState]: IExtension[]; + [state in ExtensionState]: Extension[]; }; export type GroupedByLanguage = { - [language in DefaultLanguage]: IExtension[]; + [language in DefaultLanguage]: Extension[]; } & { - [language: string]: IExtension[]; + [language: string]: Extension[]; }; export type GroupedExtensions = GroupedByExtensionState & GroupedByLanguage; diff --git a/src/typings.ts b/src/typings.ts index d3c227f6..f3054f94 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -10,6 +10,7 @@ import { OverridableComponent } from '@mui/material/OverridableComponent'; import { SvgIconTypeMap } from '@mui/material/SvgIcon/SvgIcon'; import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; +import { ExtensionType } from '@/lib/graphql/generated/graphql.ts'; type GenericLocation = Omit & { state?: State }; @@ -21,19 +22,7 @@ declare module 'react-router-dom' { export type TranslationKey = ParseKeys; -export interface IExtension { - name: string; - pkgName: string; - versionName: string; - versionCode: number; - lang: string; - isNsfw: boolean; - apkName: string; - iconUrl: string; - installed: boolean; - hasUpdate: boolean; - obsolete: boolean; -} +export type Extension = Omit; export interface ISource { id: string; From e1f338d0132e2970d9e4467b94a133fae2aebf72 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:29:19 +0200 Subject: [PATCH 17/47] Use gql for "sources" --- src/lib/requests/RequestManager.ts | 19 ++++++++++++++----- src/screens/SearchAll.tsx | 3 ++- src/screens/SourceMangas.tsx | 3 ++- src/screens/Sources.tsx | 3 ++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 84df632c..203d9f61 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -29,7 +29,6 @@ import { IManga, IMangaChapter, IncludeInGlobalUpdate, - ISource, ISourceFilters, IUpdateStatus, PaginatedList, @@ -51,6 +50,10 @@ import { GetExtensionsQueryVariables, GetGlobalMetadatasQuery, GetGlobalMetadatasQueryVariables, + GetSourceQuery, + GetSourceQueryVariables, + GetSourcesQuery, + GetSourcesQueryVariables, InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables, SetGlobalMetadataMutation, @@ -68,6 +71,7 @@ import { INSTALL_EXTERNAL_EXTENSION, UPDATE_EXTENSION, } from '@/lib/graphql/mutations/ExtensionMutation.ts'; +import { GET_SOURCE, GET_SOURCES } from '@/lib/graphql/queries/SourceQuery.ts'; enum SWRHttpMethod { SWR_GET, @@ -513,12 +517,17 @@ export class RequestManager { return this.getValidImgUrlFor(`extension/icon/${extension}`); } - public useGetSourceList(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'source/list', { swrOptions }); + public useGetSourceList( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_SOURCES, {}, options); } - public useGetSource(sourceId: string, swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `source/${sourceId}`, { swrOptions }); + public useGetSource( + id: string, + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_SOURCE, { id }, options); } public useGetSourcePopularMangas( diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index 78f27d3a..1a337a30 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -169,7 +169,8 @@ const SearchAll: React.FC = () => { const [shownLangs, setShownLangs] = useLocalStorage('shownSourceLangs', sourceDefualtLangs()); const [showNsfw] = useLocalStorage('showNsfw', true); - const { data: sources = [] } = requestManager.useGetSourceList(); + const { data } = requestManager.useGetSourceList(); + const sources = data?.sources.nodes ?? []; const [sourceToLoadingStateMap, setSourceToLoadingStateMap] = useState(new Map()); const debouncedSourceToLoadingStateMap = useDebounce(sourceToLoadingStateMap, 500); diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index 187a0df1..038360b8 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -188,7 +188,8 @@ export default function SourceMangas() { abortRequest, } = useSourceManga(sourceId, contentType, searchTerm, filtersToApply, isLargeScreen ? 2 : 1); const { data: filters = [], mutate: mutateFilters } = requestManager.useGetSourceFilters(sourceId); - const { data: source } = requestManager.useGetSource(sourceId); + const { data } = requestManager.useGetSource(sourceId); + const source = data?.source; const [triggerDataRefresh, setTriggerDataRefresh] = useState(false); const message = !isLoading ? t(SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY[contentType]) : undefined; diff --git a/src/screens/Sources.tsx b/src/screens/Sources.tsx index 1143a10a..c4412c9c 100644 --- a/src/screens/Sources.tsx +++ b/src/screens/Sources.tsx @@ -53,7 +53,8 @@ export default function Sources() { const [shownLangs, setShownLangs] = useLocalStorage('shownSourceLangs', sourceDefualtLangs()); const [showNsfw] = useLocalStorage('showNsfw', true); - const { data: sources, isLoading } = requestManager.useGetSourceList(); + const { data, loading: isLoading } = requestManager.useGetSourceList(); + const sources = data?.sources.nodes; const navigate = useNavigate(); From c75e184c5741799c20a76df185762534a3743d06 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:33:35 +0200 Subject: [PATCH 18/47] Use gql for "updating mangas" --- src/components/manga/MangaDetails.tsx | 8 +- .../navbar/action/CategorySelect.tsx | 17 +++- src/lib/requests/RequestManager.ts | 85 +++++++++++-------- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/src/components/manga/MangaDetails.tsx b/src/components/manga/MangaDetails.tsx index 4fa4a125..22aa6daa 100644 --- a/src/components/manga/MangaDetails.tsx +++ b/src/components/manga/MangaDetails.tsx @@ -152,12 +152,16 @@ const MangaDetails: React.FC = ({ manga }) => { const addToLibrary = () => { mutate(`/api/v1/manga/${manga.id}`, { ...manga, inLibrary: true }, { revalidate: false }); - requestManager.addMangaToLibrary(manga.id).response.then(() => mutate(`/api/v1/manga/${manga.id}`)); + requestManager + .updateManga(manga.id, { inLibrary: true }) + .response.then(() => mutate(`/api/v1/manga/${manga.id}`)); }; const removeFromLibrary = () => { mutate(`/api/v1/manga/${manga.id}`, { ...manga, inLibrary: false }, { revalidate: false }); - requestManager.removeMangaFromLibrary(manga.id).response.then(() => mutate(`/api/v1/manga/${manga.id}`)); + requestManager + .updateManga(manga.id, { inLibrary: false }) + .response.then(() => mutate(`/api/v1/manga/${manga.id}`)); }; return ( diff --git a/src/components/navbar/action/CategorySelect.tsx b/src/components/navbar/action/CategorySelect.tsx index 218e58a6..467e688e 100644 --- a/src/components/navbar/action/CategorySelect.tsx +++ b/src/components/navbar/action/CategorySelect.tsx @@ -31,6 +31,7 @@ export default function CategorySelect(props: IProps) { const { data: mangaCategoriesData, mutate } = requestManager.useGetMangaCategories(mangaId); const { data: categoriesData } = requestManager.useGetCategories(); + const [triggerMutate] = requestManager.useUpdateMangaCategories(); const allCategories = useMemo(() => { const cats = [...(categoriesData ?? [])]; // make copy @@ -53,10 +54,18 @@ export default function CategorySelect(props: IProps) { const handleChange = (event: React.ChangeEvent, categoryId: number) => { const { checked } = event.target as HTMLInputElement; - (checked - ? requestManager.addMangaToCategory(mangaId, categoryId) - : requestManager.removeMangaFromCategory(mangaId, categoryId) - ).response.then(() => mutate()); + // TODO - update to only update categories when clicking OK - can now be updated in one go with graphql + triggerMutate({ + variables: { + input: { + id: mangaId, + patch: { + addToCategories: checked ? [categoryId] : [], + removeFromCategories: !checked ? [categoryId] : [], + }, + }, + }, + }).then(() => mutate()); }; return ( diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 203d9f61..d27d3330 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -58,9 +58,15 @@ import { InstallExternalExtensionMutationVariables, SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, + SetMangaMetadataMutation, UpdateExtensionMutation, UpdateExtensionMutationVariables, UpdateExtensionPatchInput, + UpdateMangaCategoriesMutation, + UpdateMangaCategoriesMutationVariables, + UpdateMangaMutation, + UpdateMangaMutationVariables, + UpdateMangaPatchInput, } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; @@ -72,6 +78,10 @@ import { UPDATE_EXTENSION, } from '@/lib/graphql/mutations/ExtensionMutation.ts'; import { GET_SOURCE, GET_SOURCES } from '@/lib/graphql/queries/SourceQuery.ts'; +import { SET_MANGA_METADATA, UPDATE_MANGA, UPDATE_MANGA_CATEGORIES } from '@/lib/graphql/mutations/MangaMutation.ts'; +import { GET_MANGA, GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts'; +import { GET_CATEGORIES, GET_CATEGORY, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; +import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts'; enum SWRHttpMethod { SWR_GET, @@ -661,24 +671,51 @@ export class RequestManager { return this.doRequest(HttpMethod.SWR_GET, `manga/${mangaId}/category`, { swrOptions }); } - public addMangaToCategory(mangaId: number, categoryId: number): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `manga/${mangaId}/category/${categoryId}`); + public useUpdateMangaCategories( + options?: MutationHookOptions, + ): AbortableApolloUseMutationResponse { + return this.doRequestNew(GQLMethod.USE_MUTATION, UPDATE_MANGA_CATEGORIES, undefined, { + refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY, GET_CATEGORIES, GET_CATEGORY_MANGAS], + ...options, + }); } - public removeMangaFromCategory(mangaId: number, categoryId: number): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, `manga/${mangaId}/category/${categoryId}`); + public updateManga( + id: number, + patch: UpdateMangaPatchInput, + options?: MutationHookOptions, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_MANGA, + { input: { id, patch } }, + { + refetchQueries: [ + GET_MANGA, + GET_MANGAS, + GET_CATEGORY_MANGAS, + GET_CATEGORY, + GET_CATEGORIES, + GET_SOURCE_MANGAS_FETCH, + ], + ...options, + }, + ); } - public addMangaToLibrary(mangaId: number | string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `manga/${mangaId}/library`); - } - - public removeMangaFromLibrary(mangaId: number | string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, `manga/${mangaId}/library`); - } - - public setMangaMeta(mangaId: number, key: string, value: any): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `manga/${mangaId}/meta`, { formData: { key, value } }); + public setMangaMeta( + mangaId: number, + key: string, + value: any, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + SET_MANGA_METADATA, + { + input: { meta: { mangaId, key, value: `${value}` } }, + }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY_MANGAS, GET_SOURCE_MANGAS_FETCH] }, + ); } public useGetMangaChapters( @@ -696,26 +733,6 @@ export class RequestManager { return this.doRequest(HttpMethod.GET, `manga/${mangaId}/chapters${onlineFetch}`); } - public updateMangaChapters( - mangaId: number | string, - { - chapterIds, - chapterIndexes, - change, - }: ( - | { chapterIds?: number[]; chapterIndexes: number[] } - | { chapterIds: number[]; chapterIndexes?: number[] } - ) & { change: BatchChaptersChange }, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, `manga/${mangaId}/chapter/batch`, { - data: { - chapterIds, - chapterIndexes, - change, - }, - }); - } - public useGetChapter( mangaId: number | string, chapterIndex: number | string, From f0d55c01c861821e20671155acd1966c4e98b671 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:36:40 +0200 Subject: [PATCH 19/47] Use gql for "updating chapters" --- src/components/manga/ChapterCard.tsx | 33 +++++++++---- src/components/manga/ChapterList.tsx | 16 ++++-- src/lib/requests/RequestManager.ts | 73 ++++++++++++++++++++++------ src/screens/DownloadQueue.tsx | 2 +- src/screens/Reader.tsx | 10 ++-- src/typings.ts | 7 --- src/util/metadata.ts | 2 +- 7 files changed, 99 insertions(+), 44 deletions(-) diff --git a/src/components/manga/ChapterCard.tsx b/src/components/manga/ChapterCard.tsx index 072c3caf..1d011a47 100644 --- a/src/components/manga/ChapterCard.tsx +++ b/src/components/manga/ChapterCard.tsx @@ -31,9 +31,11 @@ import { IChapter, IDownloadChapter } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { getUploadDateString } from '@/util/date'; import DownloadStateIndicator from '@/components/molecules/DownloadStateIndicator'; +import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; interface IProps { chapter: IChapter; + chapterIds: number[]; triggerChaptersUpdate: () => void; downloadChapter: IDownloadChapter | undefined; showChapterNumber: boolean; @@ -45,7 +47,15 @@ const ChapterCard: React.FC = (props: IProps) => { const { t } = useTranslation(); const theme = useTheme(); - const { chapter, triggerChaptersUpdate, downloadChapter: dc, showChapterNumber, onSelect, selected } = props; + const { + chapter, + chapterIds, + triggerChaptersUpdate, + downloadChapter: dc, + showChapterNumber, + onSelect, + selected, + } = props; const isSelecting = selected !== null; const [anchorEl, setAnchorEl] = React.useState(null); @@ -62,13 +72,20 @@ const ChapterCard: React.FC = (props: IProps) => { setAnchorEl(null); }; - const sendChange = (key: string, value: any) => { + type UpdatePatchInput = UpdateChapterPatchInput & { markPrevRead?: boolean }; + const sendChange = (key: Key, value: UpdatePatchInput[Key]) => { handleClose(); + if (key === 'markPrevRead') { + const index = chapterIds.findIndex((chapterId) => chapterId === chapter.id); + requestManager.updateChapters(chapterIds.slice(index, -1), { isRead: true }); + return; + } + requestManager - .updateChapter(chapter.mangaId, chapter.index, { + .updateChapter(chapter.id, { [key]: value, - lastPageRead: key === 'read' ? 0 : undefined, + lastPageRead: key === 'isRead' ? 0 : undefined, }) .response.then(() => triggerChaptersUpdate()); }; @@ -79,9 +96,7 @@ const ChapterCard: React.FC = (props: IProps) => { }; const deleteChapter = () => { - requestManager - .deleteDownloadedChapter(chapter.mangaId, chapter.index) - .response.then(() => triggerChaptersUpdate()); + requestManager.deleteDownloadedChapter(chapter.id).response.then(() => triggerChaptersUpdate()); handleClose(); }; @@ -177,7 +192,7 @@ const ChapterCard: React.FC = (props: IProps) => { {t('chapter.action.download.add.label.action')} )} - sendChange('bookmarked', !chapter.bookmarked)}> + sendChange('isBookmarked', !chapter.bookmarked)}> {chapter.bookmarked && } {!chapter.bookmarked && } @@ -187,7 +202,7 @@ const ChapterCard: React.FC = (props: IProps) => { {!chapter.bookmarked && t('chapter.action.bookmark.add.label.action')} - sendChange('read', !chapter.read)}> + sendChange('isRead', !chapter.read)}> {chapter.read && } {!chapter.read && } diff --git a/src/components/manga/ChapterList.tsx b/src/components/manga/ChapterList.tsx index 1d76f5a5..21b5b8e4 100644 --- a/src/components/manga/ChapterList.tsx +++ b/src/components/manga/ChapterList.tsx @@ -11,7 +11,7 @@ import Typography from '@mui/material/Typography'; import React, { ComponentProps, useEffect, useMemo, useRef, useState } from 'react'; import { Virtuoso } from 'react-virtuoso'; import { useTranslation } from 'react-i18next'; -import { BatchChaptersChange, IChapter, IDownloadChapter, IQueue, TranslationKey } from '@/typings'; +import { IChapter, IDownloadChapter, IQueue, TranslationKey } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import useSubscription from '@/components/library/useSubscription'; import ChapterCard from '@/components/manga/ChapterCard'; @@ -22,6 +22,7 @@ import makeToast from '@/components/util/Toast'; import ChaptersToolbarMenu from '@/components/manga/ChaptersToolbarMenu'; import SelectionFAB from '@/components/manga/SelectionFAB'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab'; +import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; const StyledVirtuoso = styled(Virtuoso)(({ theme }) => ({ listStyle: 'none', @@ -87,6 +88,7 @@ const ChapterList: React.FC = ({ mangaId }) => { const [options, dispatch] = useChapterOptions(mangaId); const { data: chaptersData, mutate, isLoading } = requestManager.useGetMangaChapters(mangaId); const chapters = useMemo(() => chaptersData ?? [], [chaptersData]); + const mangaChapterIds = useMemo(() => chapters.map((chapter) => chapter.id), [chapters]); useEffect(() => { if (prevQueueRef.current && queue) { @@ -154,17 +156,20 @@ const ChapterList: React.FC = ({ mangaId }) => { if (action === 'download') { actionPromise = requestManager.addChaptersToDownloadQueue(chapterIds).response; } else { - const change: BatchChaptersChange = {}; + const change: UpdateChapterPatchInput = {}; - if (action === 'delete') change.delete = true; - else if (action === 'bookmark') change.isBookmarked = true; + if (action === 'bookmark') change.isBookmarked = true; else if (action === 'unbookmark') change.isBookmarked = false; else if (action === 'mark_as_read' || action === 'mark_as_unread') { change.isRead = action === 'mark_as_read'; change.lastPageRead = 0; } - actionPromise = requestManager.updateChapters(chapterIds, change).response; + if (action === 'delete') { + actionPromise = requestManager.deleteDownloadedChapters(chapterIds).response; + } else { + actionPromise = requestManager.updateChapters(chapterIds, change).response; + } } actionPromise @@ -266,6 +271,7 @@ const ChapterList: React.FC = ({ mangaId }) => { return ( mutate()} onSelect={() => handleSelection(index)} diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index d27d3330..85f81298 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -23,7 +23,6 @@ import { import { OperationVariables } from '@apollo/client/core'; import { BackupValidationResult, - BatchChaptersChange, ICategory, IChapter, IManga, @@ -42,6 +41,10 @@ import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; import { CheckForServerUpdatesQuery, CheckForServerUpdatesQueryVariables, + DeleteDownloadedChapterMutation, + DeleteDownloadedChapterMutationVariables, + DeleteDownloadedChaptersMutation, + DeleteDownloadedChaptersMutationVariables, GetAboutQuery, GetAboutQueryVariables, GetExtensionsFetchMutation, @@ -56,9 +59,16 @@ import { GetSourcesQueryVariables, InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables, + SetChapterMetadataMutation, + SetChapterMetadataMutationVariables, SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, SetMangaMetadataMutation, + UpdateChapterMutation, + UpdateChapterMutationVariables, + UpdateChapterPatchInput, + UpdateChaptersMutation, + UpdateChaptersMutationVariables, UpdateExtensionMutation, UpdateExtensionMutationVariables, UpdateExtensionPatchInput, @@ -82,6 +92,9 @@ import { SET_MANGA_METADATA, UPDATE_MANGA, UPDATE_MANGA_CATEGORIES } from '@/lib import { GET_MANGA, GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts'; import { GET_CATEGORIES, GET_CATEGORY, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts'; +import { DELETE_DOWNLOADED_CHAPTER, DELETE_DOWNLOADED_CHAPTERS } from '@/lib/graphql/mutations/DownloaderMutation.ts'; +import { GET_CHAPTER, GET_CHAPTERS } from '@/lib/graphql/queries/ChapterQuery.ts'; +import { SET_CHAPTER_METADATA, UPDATE_CHAPTER, UPDATE_CHAPTERS } from '@/lib/graphql/mutations/ChapterMutation.ts'; enum SWRHttpMethod { SWR_GET, @@ -747,27 +760,47 @@ export class RequestManager { return this.doRequest(HttpMethod.GET, `manga/${mangaId}/chapter/${chapterIndex}`); } - public deleteDownloadedChapter(mangaId: number | string, chapterIndex: number | string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, `manga/${mangaId}/chapter/${chapterIndex}`); + public deleteDownloadedChapter(id: number): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + DELETE_DOWNLOADED_CHAPTER, + { input: { id } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY_MANGAS, GET_CHAPTERS] }, + ); + } + + public deleteDownloadedChapters(ids: number[]): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + DELETE_DOWNLOADED_CHAPTERS, + { input: { ids } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY_MANGAS, GET_CHAPTERS] }, + ); } public updateChapter( - mangaId: number | string, - chapterIndex: number | string, - change: { read?: boolean; bookmarked?: boolean; markPrevRead?: boolean; lastPageRead?: number } = {}, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `manga/${mangaId}/chapter/${chapterIndex}`, { formData: change }); + id: number, + patch: UpdateChapterPatchInput, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_CHAPTER, + { input: { id, patch } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY_MANGAS, GET_CHAPTER, GET_CHAPTERS] }, + ); } public setChapterMeta( - mangaId: number | string, - chapterIndex: number | string, + chapterId: number, key: string, value: any, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `manga/${mangaId}/chapter/${chapterIndex}/meta`, { - formData: { key, value }, - }); + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + SET_CHAPTER_METADATA, + { input: { meta: { chapterId, key, value: `${value}` } } }, + { refetchQueries: [GET_CHAPTER, GET_CHAPTERS] }, + ); } public getChapterPageUrl(mangaId: number | string, chapterIndex: number | string, page: number): string { @@ -777,8 +810,16 @@ export class RequestManager { ); } - public updateChapters(chapterIds: number[], change: BatchChaptersChange): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, `chapter/batch`, { data: { chapterIds, change } }); + public updateChapters( + ids: number[], + patch: UpdateChapterPatchInput, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_CHAPTERS, + { input: { ids, patch } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY_MANGAS, GET_CHAPTER, GET_CHAPTERS] }, + ); } public useGetCategories(swrOptions?: SWROptions): AbortableSWRResponse { diff --git a/src/screens/DownloadQueue.tsx b/src/screens/DownloadQueue.tsx index adbb469f..21b8dd8b 100644 --- a/src/screens/DownloadQueue.tsx +++ b/src/screens/DownloadQueue.tsx @@ -74,7 +74,7 @@ const DownloadQueue: React.FC = () => { requestManager.removeChapterFromDownloadQueue(chapter.mangaId, chapter.index).response, // delete partial download, should be handle server side? // bug: The folder and the last image downloaded are not deleted - requestManager.deleteDownloadedChapter(chapter.mangaId, chapter.index).response, + requestManager.deleteDownloadedChapter(chapter.id).response, ]); } catch (error) { makeToast(t('download.queue.error.label.failed_to_remove'), 'error'); diff --git a/src/screens/Reader.tsx b/src/screens/Reader.tsx index ac2489f5..d86b65a9 100644 --- a/src/screens/Reader.tsx +++ b/src/screens/Reader.tsx @@ -85,7 +85,7 @@ const initialChapter = { chapterCount: 0, lastPageRead: 0, name: 'Loading...', -}; +} as IChapter; export default function Reader() { const { t } = useTranslation(); @@ -207,19 +207,19 @@ export default function Reader() { // do not mutate the chapter, this will cause the page to jump around due to always scrolling to the last read page if (curPage !== -1) { - requestManager.updateChapter(manga.id, chapter.index, { lastPageRead: curPage }); + requestManager.updateChapter(chapter.id, { lastPageRead: curPage }); } if (curPage === chapter.pageCount - 1) { - requestManager.updateChapter(manga.id, chapter.index, { read: true }); + requestManager.updateChapter(chapter.id, { isRead: true }); } }, [curPage]); const nextChapter = useCallback(() => { if (chapter.index < chapter.chapterCount) { - requestManager.updateChapter(manga.id, chapter.index, { + requestManager.updateChapter(chapter.id, { lastPageRead: chapter.pageCount - 1, - read: true, + isRead: true, }); openNextChapter(ChapterOffset.NEXT, (nextChapterIndex) => diff --git a/src/typings.ts b/src/typings.ts index f3054f94..a052f78c 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -368,13 +368,6 @@ export interface LibraryOptions { showTabSize: boolean; } -export interface BatchChaptersChange { - delete?: boolean; - isRead?: boolean; - isBookmarked?: boolean; - lastPageRead?: number; -} - export type UpdateCheck = { channel: 'Stable' | 'Preview'; tag: string; diff --git a/src/util/metadata.ts b/src/util/metadata.ts index acd2233d..dd69538b 100644 --- a/src/util/metadata.ts +++ b/src/util/metadata.ts @@ -315,7 +315,7 @@ export const requestUpdateMetadataValue = async ( // eslint-disable-next-line no-case-declarations const { manga, chapter } = metadataHolder as IMangaChapter; endpoint = `manga/${manga.id}/chapter/${chapter.index}/meta`; - await requestManager.setChapterMeta(manga.id, chapter.index, metadataKey, value).response; + await requestManager.setChapterMeta(chapter.id, metadataKey, value).response; break; case 'global': endpoint = 'meta'; From ca18e750bf83e883714a39e1327d25b6349e5a6f Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:39:30 +0200 Subject: [PATCH 20/47] Use gql for "categories" --- .../navbar/action/CategorySelect.tsx | 3 +- src/lib/requests/RequestManager.ts | 90 ++++++++++++++----- src/screens/Library.tsx | 12 ++- src/screens/settings/Categories.tsx | 24 ++--- src/screens/settings/LibrarySettings.tsx | 60 ++++++++----- 5 files changed, 132 insertions(+), 57 deletions(-) diff --git a/src/components/navbar/action/CategorySelect.tsx b/src/components/navbar/action/CategorySelect.tsx index 467e688e..7087fe63 100644 --- a/src/components/navbar/action/CategorySelect.tsx +++ b/src/components/navbar/action/CategorySelect.tsx @@ -30,7 +30,8 @@ export default function CategorySelect(props: IProps) { const { open, setOpen, mangaId } = props; const { data: mangaCategoriesData, mutate } = requestManager.useGetMangaCategories(mangaId); - const { data: categoriesData } = requestManager.useGetCategories(); + const { data } = requestManager.useGetCategories(); + const categoriesData = data?.categories.nodes; const [triggerMutate] = requestManager.useUpdateMangaCategories(); const allCategories = useMemo(() => { diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 85f81298..f6521af4 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -27,7 +27,6 @@ import { IChapter, IManga, IMangaChapter, - IncludeInGlobalUpdate, ISourceFilters, IUpdateStatus, PaginatedList, @@ -39,8 +38,14 @@ import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/ import storage from '@/util/localStorage.tsx'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; import { + CategoryOrderBy, CheckForServerUpdatesQuery, CheckForServerUpdatesQueryVariables, + CreateCategoryInput, + CreateCategoryMutation, + CreateCategoryMutationVariables, + DeleteCategoryMutation, + DeleteCategoryMutationVariables, DeleteDownloadedChapterMutation, DeleteDownloadedChapterMutationVariables, DeleteDownloadedChaptersMutation, @@ -49,6 +54,8 @@ import { GetAboutQueryVariables, GetExtensionsFetchMutation, GetExtensionsFetchMutationVariables, + GetCategoriesQuery, + GetCategoriesQueryVariables, GetExtensionsQuery, GetExtensionsQueryVariables, GetGlobalMetadatasQuery, @@ -59,11 +66,18 @@ import { GetSourcesQueryVariables, InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables, + SetCategoryMetadataMutation, + SetCategoryMetadataMutationVariables, SetChapterMetadataMutation, SetChapterMetadataMutationVariables, SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, SetMangaMetadataMutation, + UpdateCategoryMutation, + UpdateCategoryMutationVariables, + UpdateCategoryOrderMutation, + UpdateCategoryOrderMutationVariables, + UpdateCategoryPatchInput, UpdateChapterMutation, UpdateChapterMutationVariables, UpdateChapterPatchInput, @@ -95,6 +109,13 @@ import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation. import { DELETE_DOWNLOADED_CHAPTER, DELETE_DOWNLOADED_CHAPTERS } from '@/lib/graphql/mutations/DownloaderMutation.ts'; import { GET_CHAPTER, GET_CHAPTERS } from '@/lib/graphql/queries/ChapterQuery.ts'; import { SET_CHAPTER_METADATA, UPDATE_CHAPTER, UPDATE_CHAPTERS } from '@/lib/graphql/mutations/ChapterMutation.ts'; +import { + CREATE_CATEGORY, + DELETE_CATEGORY, + SET_CATEGORY_METADATA, + UPDATE_CATEGORY, + UPDATE_CATEGORY_ORDER, +} from '@/lib/graphql/mutations/CategoryMutation.ts'; enum SWRHttpMethod { SWR_GET, @@ -822,37 +843,66 @@ export class RequestManager { ); } - public useGetCategories(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `category`, { swrOptions }); - } - - public createCategory(name: string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, `category`, { formData: { name } }); - } - - public reorderCategory(currentPosition: number, newPosition: number): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `category/reorder`, { - formData: { from: currentPosition, to: newPosition }, + public useGetCategories(): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_CATEGORIES, { + orderBy: CategoryOrderBy.Order, }); } + public createCategory(input: CreateCategoryInput): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + CREATE_CATEGORY, + { input }, + { refetchQueries: [GET_CATEGORIES] }, + ); + } + + public reorderCategory(id: number, position: number): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_CATEGORY_ORDER, + { input: { id, position } }, + { refetchQueries: [GET_CATEGORIES] }, + ); + } + public useGetCategoryMangas(categoryId: number, swrOptions?: SWROptions): AbortableSWRResponse { return this.doRequest(HttpMethod.SWR_GET, `category/${categoryId}`, { swrOptions }); } - public deleteCategory(categoryId: number): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, `category/${categoryId}`); + public deleteCategory(categoryId: number): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + DELETE_CATEGORY, + { input: { categoryId } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORIES] }, + ); } public updateCategory( - categoryId: number, - change: { name?: string; default?: boolean; includeInUpdate?: IncludeInGlobalUpdate } = {}, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `category/${categoryId}`, { formData: change }); + id: number, + patch: UpdateCategoryPatchInput, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_CATEGORY, + { input: { id, patch } }, + { refetchQueries: [GET_CATEGORY, GET_CATEGORIES] }, + ); } - public setCategoryMeta(categoryId: number, key: string, value: any): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `category/${categoryId}/meta`, { formData: { key, value } }); + public setCategoryMeta( + categoryId: number, + key: string, + value: any, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + SET_CATEGORY_METADATA, + { input: { meta: { categoryId, key, value: `${value}` } } }, + { refetchQueries: [GET_MANGA, GET_MANGAS, GET_CATEGORY, GET_CATEGORIES] }, + ); } public restoreBackupFile(file: File): AbortableAxiosResponse { diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index b6722da2..ecaf4279 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -63,9 +63,13 @@ export default function Library() { const { options } = useLibraryOptionsContext(); const [lastLibraryUpdate, setLastLibraryUpdate] = useState(Date.now()); - const { data: tabsData, error: tabsError, isLoading: areCategoriesLoading } = requestManager.useGetCategories(); + const { data, error: tabsError, loading: areCategoriesLoading } = requestManager.useGetCategories(); + const tabsData = data?.categories.nodes.filter((category) => category.id !== 0); const tabs = tabsData ?? []; - const librarySize = useMemo(() => tabs.map((tab) => tab.size).reduce((prev, curr) => prev + curr, 0), [tabs]); + const librarySize = useMemo( + () => tabs.map((tab) => tab.mangas.totalCount).reduce((prev, curr) => prev + curr, 0), + [tabs], + ); const [tabSearchParam, setTabSearchParam] = useQueryParam('tab', NumberParam); @@ -108,7 +112,7 @@ export default function Library() { return ( ); } @@ -154,7 +158,7 @@ export default function Library() { label={ {tab.name} - {options.showTabSize ? : null} + {options.showTabSize ? : null} } value={tab.order} diff --git a/src/screens/settings/Categories.tsx b/src/screens/settings/Categories.tsx index 938bfec3..001e4691 100644 --- a/src/screens/settings/Categories.tsx +++ b/src/screens/settings/Categories.tsx @@ -24,11 +24,11 @@ import DialogTitle from '@mui/material/DialogTitle'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import { useTranslation } from 'react-i18next'; -import { ICategory } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import StrictModeDroppable from '@/lib/StrictModeDroppable'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; +import { CategoryType } from '@/lib/graphql/generated/graphql.ts'; const getItemStyle = ( isDragging: boolean, @@ -52,13 +52,13 @@ export default function Categories() { setAction(null); }, [t]); - const { data, mutate } = requestManager.useGetCategories(); + const { data } = requestManager.useGetCategories(); const categories = useMemo(() => { - const res = [...(data ?? [])]; + const res = [...(data?.categories.nodes ?? [])]; if (res.length > 0 && res[0].name === 'Default') { res.shift(); } - return res; + return res as CategoryType[]; }, [data]); const [categoryToEdit, setCategoryToEdit] = useState(-1); // -1 means new category @@ -69,13 +69,15 @@ export default function Categories() { useSetDefaultBackTo('settings'); - const categoryReorder = (list: ICategory[], from: number, to: number) => { + const categoryReorder = (list: CategoryType[], from: number, to: number) => { + const reorderedCategory = list[from]; const newData = [...list]; const [removed] = newData.splice(from, 1); newData.splice(to, 0, removed); - mutate(newData, { revalidate: false }); + // TODO - update cache immediately + // mutate(categoriesEndpoint, newData, { revalidate: false }); - requestManager.reorderCategory(from + 1, to + 1).response.finally(() => mutate()); + requestManager.reorderCategory(reorderedCategory.id, to + 1); }; const onDragEnd = (result: DropResult) => { @@ -113,18 +115,16 @@ export default function Categories() { setDialogOpen(false); if (categoryToEdit === -1) { - requestManager.createCategory(dialogName).response.finally(() => mutate()); + requestManager.createCategory({ name: dialogName, default: dialogDefault }); } else { const category = categories[categoryToEdit]; - requestManager - .updateCategory(category.id, { name: dialogName, default: dialogDefault }) - .response.finally(() => mutate()); + requestManager.updateCategory(category.id, { name: dialogName, default: dialogDefault }); } }; const deleteCategory = (index: number) => { const category = categories[index]; - requestManager.deleteCategory(category.id).response.finally(() => mutate()); + requestManager.deleteCategory(category.id); }; return ( diff --git a/src/screens/settings/LibrarySettings.tsx b/src/screens/settings/LibrarySettings.tsx index e690ced7..fa601885 100644 --- a/src/screens/settings/LibrarySettings.tsx +++ b/src/screens/settings/LibrarySettings.tsx @@ -20,12 +20,12 @@ import DialogTitle from '@mui/material/DialogTitle'; import { styled } from '@mui/material'; import { t as translate } from 'i18next'; import { useTranslation } from 'react-i18next'; -import { ICategory, IncludeInGlobalUpdate } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; import ThreeStateCheckboxInput from '@/components/atoms/ThreeStateCheckboxInput'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; import SearchSettings from '@/screens/settings/SearchSettings'; +import { CategoryType, IncludeInUpdate } from '@/lib/graphql/generated/graphql.ts'; const CategoriesDiv = styled('div')({ display: 'flex', @@ -34,16 +34,35 @@ const CategoriesDiv = styled('div')({ overflow: 'auto', }); -const includeInUpdateStatusToBoolean = (status: IncludeInGlobalUpdate) => { - if (status === IncludeInGlobalUpdate.UNSET) { - return null; +const booleanToIncludeInStatus = (status: boolean | null | undefined): IncludeInUpdate => { + switch (status) { + case false: + return IncludeInUpdate.Exclude; + case true: + return IncludeInUpdate.Include; + case null: + case undefined: + return IncludeInUpdate.Unset; + default: + throw new Error(`booleanToIncludeInStatus: unexpected IncludeInUpdate status "${status}"`); } +}; - return !!status; +const includeInUpdateStatusToBoolean = (status: IncludeInUpdate): boolean | null => { + switch (status) { + case IncludeInUpdate.Exclude: + return false; + case IncludeInUpdate.Include: + return true; + case IncludeInUpdate.Unset: + return null; + default: + throw new Error(`includeInUpdateStatusToBoolean: unexpected IncludeInUpdate status "${status}"`); + } }; const getCategoryUpdateInfo = ( - categories: ICategory[], + categories: CategoryType[], areIncluded: boolean, unsetCategories: number, allCategories: number, @@ -80,20 +99,21 @@ export default function LibrarySettings() { useSetDefaultBackTo('settings'); - const { data: categories = [], error: requestError, mutate } = requestManager.useGetCategories(); - const [dialogCategories, setDialogCategories] = useState(categories); + const { data, error: requestError } = requestManager.useGetCategories(); + const categories = (data?.categories.nodes ?? []) as CategoryType[]; + const [dialogCategories, setDialogCategories] = useState(categories); const [isDialogOpen, setIsDialogOpen] = useState(false); useEffect(() => { setDialogCategories(categories); }, [categories]); - const unsetCategories: ICategory[] = - categories?.filter((category) => category.includeInUpdate === IncludeInGlobalUpdate.UNSET) ?? []; - const excludedCategories: ICategory[] = - categories?.filter((category) => category.includeInUpdate === IncludeInGlobalUpdate.EXCLUDE) ?? []; - const includedCategories: ICategory[] = - categories?.filter((category) => category.includeInUpdate === IncludeInGlobalUpdate.INCLUDE) ?? []; + const unsetCategories: CategoryType[] = + categories?.filter((category) => category.includeInUpdate === IncludeInUpdate.Unset) ?? []; + const excludedCategories: CategoryType[] = + categories?.filter((category) => category.includeInUpdate === IncludeInUpdate.Exclude) ?? []; + const includedCategories: CategoryType[] = + categories?.filter((category) => category.includeInUpdate === IncludeInUpdate.Include) ?? []; const excludedCategoriesText = getCategoryUpdateInfo( excludedCategories, false, @@ -109,7 +129,7 @@ export default function LibrarySettings() { requestError, ); - const updateCategory = (category: ICategory) => + const updateCategory = (category: CategoryType) => requestManager.updateCategory(category.id, { includeInUpdate: category.includeInUpdate }).response; const updateCategories = async () => { @@ -127,10 +147,11 @@ export default function LibrarySettings() { try { await Promise.all(categoriesToUpdate.map((category) => updateCategory(category))); - mutate([...dialogCategories], { revalidate: false }); + // TODO - update cache immediately + // mutate(categoriesEndpoint, [...dialogCategories], { revalidate: false }); } catch (error) { makeToast(t('global.error.label.failed_to_save_changes'), 'error'); - mutate([...categories]); + // mutate(categoriesEndpoint, [...categories]); } }; @@ -192,13 +213,12 @@ export default function LibrarySettings() { label={category.name} checked={includeInUpdateStatusToBoolean(category.includeInUpdate)} onChange={(checked) => { - const newIncludeState: IncludeInGlobalUpdate = - checked == null ? IncludeInGlobalUpdate.UNSET : Number(checked); + const newIncludeState = booleanToIncludeInStatus(checked); const categoryIndex = dialogCategories.findIndex( (category_) => category_ === category, ); - const updatedDialogCategories: ICategory[] = [ + const updatedDialogCategories: CategoryType[] = [ ...dialogCategories.slice(0, categoryIndex), { ...category, From 222f8f5c9b2af91373fdfbf688dafa4d34eb96a0 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:40:24 +0200 Subject: [PATCH 21/47] Use gql for "downloader" --- src/components/manga/ChapterCard.tsx | 2 +- src/lib/requests/RequestManager.ts | 108 +++++++++++++++++++++------ src/screens/DownloadQueue.tsx | 2 +- src/screens/Updates.tsx | 2 +- 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/components/manga/ChapterCard.tsx b/src/components/manga/ChapterCard.tsx index 1d011a47..1b6962cb 100644 --- a/src/components/manga/ChapterCard.tsx +++ b/src/components/manga/ChapterCard.tsx @@ -91,7 +91,7 @@ const ChapterCard: React.FC = (props: IProps) => { }; const downloadChapter = () => { - requestManager.addChapterToDownloadQueue(chapter.mangaId, chapter.index); + requestManager.addChapterToDownloadQueue(chapter.id); handleClose(); }; diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index f6521af4..f9ce743f 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -41,6 +41,8 @@ import { CategoryOrderBy, CheckForServerUpdatesQuery, CheckForServerUpdatesQueryVariables, + ClearDownloaderMutation, + ClearDownloaderMutationVariables, CreateCategoryInput, CreateCategoryMutation, CreateCategoryMutationVariables, @@ -50,6 +52,14 @@ import { DeleteDownloadedChapterMutationVariables, DeleteDownloadedChaptersMutation, DeleteDownloadedChaptersMutationVariables, + DequeueChapterDownloadMutation, + DequeueChapterDownloadMutationVariables, + DequeueChapterDownloadsMutation, + DequeueChapterDownloadsMutationVariables, + EnqueueChapterDownloadMutation, + EnqueueChapterDownloadMutationVariables, + EnqueueChapterDownloadsMutation, + EnqueueChapterDownloadsMutationVariables, GetAboutQuery, GetAboutQueryVariables, GetExtensionsFetchMutation, @@ -66,6 +76,8 @@ import { GetSourcesQueryVariables, InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables, + ReorderChapterDownloadMutation, + ReorderChapterDownloadMutationVariables, SetCategoryMetadataMutation, SetCategoryMetadataMutationVariables, SetChapterMetadataMutation, @@ -73,6 +85,10 @@ import { SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, SetMangaMetadataMutation, + StartDownloaderMutation, + StartDownloaderMutationVariables, + StopDownloaderMutation, + StopDownloaderMutationVariables, UpdateCategoryMutation, UpdateCategoryMutationVariables, UpdateCategoryOrderMutation, @@ -106,7 +122,18 @@ import { SET_MANGA_METADATA, UPDATE_MANGA, UPDATE_MANGA_CATEGORIES } from '@/lib import { GET_MANGA, GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts'; import { GET_CATEGORIES, GET_CATEGORY, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts'; -import { DELETE_DOWNLOADED_CHAPTER, DELETE_DOWNLOADED_CHAPTERS } from '@/lib/graphql/mutations/DownloaderMutation.ts'; +import { + CLEAR_DOWNLOADER, + DELETE_DOWNLOADED_CHAPTER, + DELETE_DOWNLOADED_CHAPTERS, + DEQUEUE_CHAPTER_DOWNLOAD, + DEQUEUE_CHAPTER_DOWNLOADS, + ENQUEUE_CHAPTER_DOWNLOAD, + ENQUEUE_CHAPTER_DOWNLOADS, + REORDER_CHAPTER_DOWNLOAD, + START_DOWNLOADER, + STOP_DOWNLOADER, +} from '@/lib/graphql/mutations/DownloaderMutation.ts'; import { GET_CHAPTER, GET_CHAPTERS } from '@/lib/graphql/queries/ChapterQuery.ts'; import { SET_CHAPTER_METADATA, UPDATE_CHAPTER, UPDATE_CHAPTERS } from '@/lib/graphql/mutations/ChapterMutation.ts'; import { @@ -116,6 +143,7 @@ import { UPDATE_CATEGORY, UPDATE_CATEGORY_ORDER, } from '@/lib/graphql/mutations/CategoryMutation.ts'; +import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts'; enum SWRHttpMethod { SWR_GET, @@ -923,43 +951,79 @@ export class RequestManager { return this.getValidUrlFor('backup/export/file'); } - public startDownloads(): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, 'downloads/start'); + public startDownloads(): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + START_DOWNLOADER, + {}, + ); } - public stopDownloads(): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, 'downloads/stop'); + public stopDownloads(): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + STOP_DOWNLOADER, + {}, + ); } - public clearDownloads(): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, 'downloads/clear'); + public clearDownloads(): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + CLEAR_DOWNLOADER, + {}, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } - public addChapterToDownloadQueue(mangaId: number | string, chapterIndex: number | string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `download/${mangaId}/chapter/${chapterIndex}`); + public addChapterToDownloadQueue(id: number): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + ENQUEUE_CHAPTER_DOWNLOAD, + { input: { id } }, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } - public removeChapterFromDownloadQueue( - mangaId: number | string, - chapterIndex: number | string, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, `download/${mangaId}/chapter/${chapterIndex}`); + public removeChapterFromDownloadQueue(id: number): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + DEQUEUE_CHAPTER_DOWNLOAD, + { input: { id } }, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } public reorderChapterInDownloadQueue( - mangaId: number | string, - chapterIndex: number | string, + chapterId: number, position: number, - ): AbortableAxiosResponse { - return this.doRequest(HttpMethod.PATCH, `download/${mangaId}/chapter/${chapterIndex}/reorder/${position}`); + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + REORDER_CHAPTER_DOWNLOAD, + { input: { chapterId, to: position } }, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } - public addChaptersToDownloadQueue(chapterIds: number[]): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, 'download/batch', { data: { chapterIds } }); + public addChaptersToDownloadQueue(ids: number[]): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + ENQUEUE_CHAPTER_DOWNLOADS, + { input: { ids } }, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } - public removeChaptersFromDownloadQueue(chapterIds: number[]): AbortableAxiosResponse { - return this.doRequest(HttpMethod.DELETE, 'download/batch', { data: { chapterIds } }); + public removeChaptersFromDownloadQueue( + ids: number[], + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + DEQUEUE_CHAPTER_DOWNLOADS, + { input: { ids } }, + { refetchQueries: [GET_DOWNLOAD_STATUS] }, + ); } public useGetRecentlyUpdatedChapters( diff --git a/src/screens/DownloadQueue.tsx b/src/screens/DownloadQueue.tsx index 21b8dd8b..219b4c41 100644 --- a/src/screens/DownloadQueue.tsx +++ b/src/screens/DownloadQueue.tsx @@ -71,7 +71,7 @@ const DownloadQueue: React.FC = () => { await Promise.all([ // remove from download queue - requestManager.removeChapterFromDownloadQueue(chapter.mangaId, chapter.index).response, + requestManager.removeChapterFromDownloadQueue(chapter.id).response, // delete partial download, should be handle server side? // bug: The folder and the last image downloaded are not deleted requestManager.deleteDownloadedChapter(chapter.id).response, diff --git a/src/screens/Updates.tsx b/src/screens/Updates.tsx index 85e13d84..87462a91 100644 --- a/src/screens/Updates.tsx +++ b/src/screens/Updates.tsx @@ -146,7 +146,7 @@ const Updates: React.FC = () => { }; const downloadChapter = (chapter: IChapter) => { - requestManager.addChapterToDownloadQueue(chapter.mangaId, chapter.index); + requestManager.addChapterToDownloadQueue(chapter.id); }; const loadMore = useCallback(() => { From a5b4b95bce8861751a74bf3c121e32f9c19bff46 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:40:39 +0200 Subject: [PATCH 22/47] Use gql for "updater" --- src/lib/requests/RequestManager.ts | 51 ++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index f9ce743f..056d9a54 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -28,7 +28,6 @@ import { IManga, IMangaChapter, ISourceFilters, - IUpdateStatus, PaginatedList, PaginatedMangaList, SourcePreferences, @@ -74,6 +73,8 @@ import { GetSourceQueryVariables, GetSourcesQuery, GetSourcesQueryVariables, + GetUpdateStatusQuery, + GetUpdateStatusQueryVariables, InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables, ReorderChapterDownloadMutation, @@ -89,6 +90,10 @@ import { StartDownloaderMutationVariables, StopDownloaderMutation, StopDownloaderMutationVariables, + StopUpdaterMutation, + StopUpdaterMutationVariables, + UpdateCategoryMangasMutation, + UpdateCategoryMangasMutationVariables, UpdateCategoryMutation, UpdateCategoryMutationVariables, UpdateCategoryOrderMutation, @@ -102,6 +107,8 @@ import { UpdateExtensionMutation, UpdateExtensionMutationVariables, UpdateExtensionPatchInput, + UpdateLibraryMangasMutation, + UpdateLibraryMangasMutationVariables, UpdateMangaCategoriesMutation, UpdateMangaCategoriesMutationVariables, UpdateMangaMutation, @@ -144,6 +151,12 @@ import { UPDATE_CATEGORY_ORDER, } from '@/lib/graphql/mutations/CategoryMutation.ts'; import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts'; +import { + STOP_UPDATER, + UPDATE_CATEGORY_MANGAS, + UPDATE_LIBRARY_MANGAS, +} from '@/lib/graphql/mutations/UpdaterMutation.ts'; +import { GET_UPDATE_STATUS } from '@/lib/graphql/queries/UpdaterQuery.ts'; enum SWRHttpMethod { SWR_GET, @@ -1040,16 +1053,40 @@ export class RequestManager { }); } - public startGlobalUpdate(categoryId?: number): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, 'update/fetch', { formData: { categoryId } }); + public startGlobalUpdate(): AbortableApolloMutationResponse; + + public startGlobalUpdate(categories: number[]): AbortableApolloMutationResponse; + + public startGlobalUpdate( + categories?: number[], + ): AbortableApolloMutationResponse { + if (categories?.length) { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_CATEGORY_MANGAS, + { input: { categories } }, + ); + } + + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_LIBRARY_MANGAS, + {}, + ); } - public resetGlobalUpdate(): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, 'update/reset'); + public resetGlobalUpdate(): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + STOP_UPDATER, + {}, + ); } - public useGetGlobalUpdateSummary(swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, 'update/summary', { swrOptions }); + public useGetGlobalUpdateSummary( + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_UPDATE_STATUS, {}, options); } } From 89dc053f00f20832c09271b8ed3239078e03df16 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 8 Sep 2023 00:44:01 +0200 Subject: [PATCH 23/47] Use gql for "mangas" I - get manga --- src/components/manga/MangaDetails.tsx | 46 +++++++--- src/components/manga/MangaToolbarMenu.tsx | 4 +- src/components/manga/hooks.ts | 2 +- src/components/navbar/ReaderNavBar.tsx | 5 +- src/components/util/EmptyView.tsx | 2 +- src/lib/requests/RequestManager.ts | 48 ++++++----- src/screens/Manga.tsx | 27 +++--- src/screens/Reader.tsx | 32 ++++--- .../settings/DefaultReaderSettings.tsx | 10 ++- src/screens/settings/SearchSettings.tsx | 4 +- src/typings.ts | 6 +- src/util/metadata.ts | 84 ++++++++----------- src/util/readerSettings.ts | 22 ++--- src/util/searchSettings.ts | 4 +- 14 files changed, 170 insertions(+), 126 deletions(-) diff --git a/src/components/manga/MangaDetails.tsx b/src/components/manga/MangaDetails.tsx index 22aa6daa..8b148034 100644 --- a/src/components/manga/MangaDetails.tsx +++ b/src/components/manga/MangaDetails.tsx @@ -10,14 +10,15 @@ import FavoriteIcon from '@mui/icons-material/Favorite'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import PublicIcon from '@mui/icons-material/Public'; import { styled } from '@mui/material/styles'; -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { mutate } from 'swr'; import { t as translate } from 'i18next'; import Button from '@mui/material/Button'; -import { IManga, ISource } from '@/typings'; +import { ISource } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import makeToast from '@/components/util/Toast'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const DetailsWrapper = styled('div')(({ theme }) => ({ width: '100%', @@ -125,11 +126,36 @@ const Genres = styled('div')(() => ({ }, })); +const OpenSourceButton = ({ url }: { url?: string | null }) => { + const { t } = useTranslation(); + + const button = useMemo( + () => ( + + ), + [url], + ); + + if (!url) { + return button; + } + + return ( + + + + ); +}; + interface IProps { - manga: IManga; + manga: MangaType; } -function getSourceName(source: ISource) { +function getSourceName(source?: ISource | null) { if (!source) { return translate('global.label.unknown'); } @@ -137,7 +163,7 @@ function getSourceName(source: ISource) { return source.displayName ?? source.id; } -function getValueOrUnknown(val: string) { +function getValueOrUnknown(val?: string | null) { return val || 'UNKNOWN'; } @@ -169,7 +195,9 @@ const MangaDetails: React.FC = ({ manga }) => { - Manga Thumbnail + {manga.thumbnailUrl && ( + Manga Thumbnail + )}

{manga.title}

@@ -195,11 +223,7 @@ const MangaDetails: React.FC = ({ manga }) => { {manga.inLibrary ? t('manga.button.in_library') : t('manga.button.add_to_library')} - - - +
diff --git a/src/components/manga/MangaToolbarMenu.tsx b/src/components/manga/MangaToolbarMenu.tsx index 43980f94..4e035d04 100644 --- a/src/components/manga/MangaToolbarMenu.tsx +++ b/src/components/manga/MangaToolbarMenu.tsx @@ -21,11 +21,11 @@ import { } from '@mui/material'; import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { IManga } from '@/typings'; import CategorySelect from '@/components/navbar/action/CategorySelect'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; interface IProps { - manga: IManga; + manga: MangaType; onRefresh: () => any; refreshing: boolean; } diff --git a/src/components/manga/hooks.ts b/src/components/manga/hooks.ts index 2bc45b70..4327641a 100644 --- a/src/components/manga/hooks.ts +++ b/src/components/manga/hooks.ts @@ -16,7 +16,7 @@ export const useRefreshManga = (mangaId: string) => { const handleRefresh = useCallback(async () => { setFetchingOnline(true); await Promise.all([ - requestManager.getManga(mangaId, true).response.then((res) => { + requestManager.getMangaFetch(mangaId).response.then((res) => { mutate(`${RequestManager.API_VERSION}manga/${mangaId}`, res, { revalidate: false }); }), requestManager.getMangaChapters(mangaId, true).response.then((res) => diff --git a/src/components/navbar/ReaderNavBar.tsx b/src/components/navbar/ReaderNavBar.tsx index fba208aa..b95ef730 100644 --- a/src/components/navbar/ReaderNavBar.tsx +++ b/src/components/navbar/ReaderNavBar.tsx @@ -24,8 +24,9 @@ import ListItemText from '@mui/material/ListItemText'; import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; import Collapse from '@mui/material/Collapse'; import { useTranslation } from 'react-i18next'; -import { ChapterOffset, IChapter, IManga, IMangaCard, IReaderSettings } from '@/typings'; +import { ChapterOffset, IChapter, IReaderSettings } from '@/typings'; import ReaderSettingsOptions from '@/components/reader/ReaderSettingsOptions'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const Root = styled('div')(({ theme }) => ({ top: 0, @@ -114,7 +115,7 @@ const OpenDrawerButton = styled(IconButton)(({ theme }) => ({ interface IProps { settings: IReaderSettings; setSettingValue: (key: keyof IReaderSettings, value: string | boolean) => void; - manga: IManga | IMangaCard; + manga: Pick; chapter: IChapter; curPage: number; scrollToPage: (page: number) => void; diff --git a/src/components/util/EmptyView.tsx b/src/components/util/EmptyView.tsx index d2a9ad95..ee7df4c9 100644 --- a/src/components/util/EmptyView.tsx +++ b/src/components/util/EmptyView.tsx @@ -22,7 +22,7 @@ function getRandomErrorFace() { interface IProps { message: string; - messageExtra?: JSX.Element; + messageExtra?: JSX.Element | string; } export default function EmptyView({ message, messageExtra }: IProps) { diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 056d9a54..118b76a6 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -69,6 +69,10 @@ import { GetExtensionsQueryVariables, GetGlobalMetadatasQuery, GetGlobalMetadatasQueryVariables, + GetMangaFetchMutation, + GetMangaFetchMutationVariables, + GetMangaQuery, + GetMangaQueryVariables, GetSourceQuery, GetSourceQueryVariables, GetSourcesQuery, @@ -125,7 +129,12 @@ import { UPDATE_EXTENSION, } from '@/lib/graphql/mutations/ExtensionMutation.ts'; import { GET_SOURCE, GET_SOURCES } from '@/lib/graphql/queries/SourceQuery.ts'; -import { SET_MANGA_METADATA, UPDATE_MANGA, UPDATE_MANGA_CATEGORIES } from '@/lib/graphql/mutations/MangaMutation.ts'; +import { + GET_MANGA_FETCH, + SET_MANGA_METADATA, + UPDATE_MANGA, + UPDATE_MANGA_CATEGORIES, +} from '@/lib/graphql/mutations/MangaMutation.ts'; import { GET_MANGA, GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts'; import { GET_CATEGORIES, GET_CATEGORY, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts'; @@ -712,27 +721,28 @@ export class RequestManager { public useGetManga( mangaId: number | string, - { doOnlineFetch, ...swrOptions }: SWROptions & RequestOption = {}, - ): AbortableSWRResponse { - const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : ''; - return this.doRequest(HttpMethod.SWR_GET, `manga/${mangaId}${onlineFetch}`, { - swrOptions, - }); + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_MANGA, { id: Number(mangaId) }, options); } - public getManga(mangaId: number | string, doOnlineFetch?: boolean): AbortableAxiosResponse { - const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : ''; - return this.doRequest(HttpMethod.GET, `manga/${mangaId}${onlineFetch}`); - } - - public useGetFullManga( + public getMangaFetch( mangaId: number | string, - { doOnlineFetch, ...swrOptions }: SWROptions & RequestOption = {}, - ): AbortableSWRResponse { - const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : ''; - return this.doRequest(HttpMethod.SWR_GET, `manga/${mangaId}/full${onlineFetch}`, { - swrOptions, - }); + options?: MutationOptions, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + GET_MANGA_FETCH, + { + input: { + id: Number(mangaId), + }, + }, + { + refetchQueries: [GET_MANGA, GET_MANGAS], + ...options, + }, + ); } public getMangaThumbnailUrl(mangaId: number): string { diff --git a/src/screens/Manga.tsx b/src/screens/Manga.tsx index af6b0e58..aa1566b8 100644 --- a/src/screens/Manga.tsx +++ b/src/screens/Manga.tsx @@ -11,6 +11,7 @@ import { CircularProgress, IconButton, Stack, Tooltip, Box } from '@mui/material import React, { useContext, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; +import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus'; import requestManager from '@/lib/requests/RequestManager.ts'; import NavbarContext, { useSetDefaultBackTo } from '@/components/context/NavbarContext'; import ChapterList from '@/components/manga/ChapterList'; @@ -19,8 +20,9 @@ import MangaDetails from '@/components/manga/MangaDetails'; import MangaToolbarMenu from '@/components/manga/MangaToolbarMenu'; import EmptyView from '@/components/util/EmptyView'; import LoadingPlaceholder from '@/components/util/LoadingPlaceholder'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; -const AUTOFETCH_AGE = 60 * 60 * 24; // 24 hours +const AUTOFETCH_AGE = 1000 * 60 * 60 * 24; // 24 hours const Manga: React.FC = () => { const { t } = useTranslation(); @@ -29,21 +31,26 @@ const Manga: React.FC = () => { const { id } = useParams<{ id: string }>(); const autofetchedRef = useRef(false); - const { data: manga, error, isLoading, isValidating, mutate } = requestManager.useGetManga(id); + const { data, error, loading: isLoading, networkStatus, refetch } = requestManager.useGetManga(id); + const isValidating = isNetworkRequestInFlight(networkStatus); + const manga = data?.manga as MangaType | undefined; const [refresh, { loading: refreshing }] = useRefreshManga(id); useSetDefaultBackTo('library'); useEffect(() => { - // Automatically fetch manga from source if data is older then 24 hours + // Automatically fetch manga from source if data is older then 24 hours OR manga is not initialized yet // Automatic fetch is done only once, to prevent issues when server does // not update age for some reason (ie. error on source side) if (manga == null) return; - if ( - manga.inLibrary && - (manga.age > AUTOFETCH_AGE || manga.chaptersAge > AUTOFETCH_AGE) && - autofetchedRef.current === false - ) { + + const isOutdated = + Date.now() - Number(manga.lastFetchedAt) * 1000 > AUTOFETCH_AGE || + Date.now() - Number(manga.chaptersLastFetchedAt) * 1000 > AUTOFETCH_AGE; + const refetchBecauseOutdated = manga.inLibrary && isOutdated; + + const doFetch = !autofetchedRef.current && (refetchBecauseOutdated || !manga.initialized); + if (doFetch) { autofetchedRef.current = true; refresh(); } @@ -67,7 +74,7 @@ const Manga: React.FC = () => { } > - mutate()}> + refetch()}> @@ -80,7 +87,7 @@ const Manga: React.FC = () => { {manga && } , ); - }, [t, error, isValidating, refreshing, mutate, manga, refresh]); + }, [t, error, isValidating, refreshing, manga, refresh]); if (error && !manga) { return ; diff --git a/src/screens/Reader.tsx b/src/screens/Reader.tsx index d86b65a9..77178232 100644 --- a/src/screens/Reader.tsx +++ b/src/screens/Reader.tsx @@ -7,11 +7,11 @@ */ import CircularProgress from '@mui/material/CircularProgress'; -import { useCallback, useContext, useEffect, useState } from 'react'; +import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { Box } from '@mui/material'; import { useTranslation } from 'react-i18next'; -import { ChapterOffset, IChapter, IManga, IMangaCard, IReaderSettings, ReaderType, TranslationKey } from '@/typings'; +import { ChapterOffset, IChapter, IReaderSettings, ReaderType, TranslationKey } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { checkAndHandleMissingStoredReaderSettings, @@ -27,6 +27,7 @@ import VerticalPager from '@/components/reader/pager/VerticalPager'; import ReaderNavBar from '@/components/navbar/ReaderNavBar'; import NavbarContext from '@/components/context/NavbarContext'; import makeToast from '@/components/util/Toast'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const isDupChapter = async (chapterIndex: number, currentChapter: IChapter) => { const nextChapter = await requestManager.getChapter(currentChapter.mangaId, chapterIndex).response; @@ -93,17 +94,22 @@ export default function Reader() { const location = useLocation(); const { chapterIndex, mangaId } = useParams<{ chapterIndex: string; mangaId: string }>(); - const { - data: manga = { - id: +mangaId, - title: '', - thumbnailUrl: '', - genre: [], - inLibraryAt: 0, - lastReadAt: 0, - } as IMangaCard | IManga, - isLoading: isMangaLoading, - } = requestManager.useGetManga(mangaId); + + const initialManga = useMemo( + () => + ({ + id: +mangaId, + title: '', + thumbnailUrl: '', + genre: [], + inLibraryAt: 0, + lastReadAt: 0, + }) as unknown as MangaType, + [mangaId], + ); + + const { data, loading: isMangaLoading } = requestManager.useGetManga(mangaId); + const manga = (data?.manga as MangaType) ?? initialManga; const { data: chapter = initialChapter, isLoading: isChapterLoading } = requestManager.useGetChapter( mangaId, chapterIndex, diff --git a/src/screens/settings/DefaultReaderSettings.tsx b/src/screens/settings/DefaultReaderSettings.tsx index d296a5d7..a71ae4cb 100644 --- a/src/screens/settings/DefaultReaderSettings.tsx +++ b/src/screens/settings/DefaultReaderSettings.tsx @@ -11,7 +11,7 @@ import { Box } from '@mui/material'; import CircularProgress from '@mui/material/CircularProgress'; import { useTranslation } from 'react-i18next'; import { IReaderSettings } from '@/typings'; -import { requestUpdateServerMetadata } from '@/util/metadata'; +import { convertToGqlMeta, requestUpdateServerMetadata } from '@/util/metadata'; import { checkAndHandleMissingStoredReaderSettings, getDefaultSettings, @@ -34,7 +34,7 @@ export default function DefaultReaderSettings() { useSetDefaultBackTo('settings'); const setSettingValue = (key: keyof IReaderSettings, value: string | boolean) => { - requestUpdateServerMetadata(metadata ?? {}, [[key, value]]).catch(() => + requestUpdateServerMetadata(convertToGqlMeta(metadata)! ?? {}, [[key, value]]).catch(() => makeToast(t('reader.settings.error.label.failed_to_save_settings'), 'warning'), ); }; @@ -54,7 +54,11 @@ export default function DefaultReaderSettings() { ); } - checkAndHandleMissingStoredReaderSettings({ meta: metadata }, 'server', getDefaultSettings()).catch(() => {}); + checkAndHandleMissingStoredReaderSettings( + { meta: convertToGqlMeta(metadata)! }, + 'server', + getDefaultSettings(), + ).catch(() => {}); return ( { - requestUpdateServerMetadata(metadata ?? {}, [[key, value]]).catch(() => + requestUpdateServerMetadata(convertToGqlMeta(metadata)! ?? {}, [[key, value]]).catch(() => makeToast(t('search.error.label.failed_to_save_settings'), 'warning'), ); }; diff --git a/src/typings.ts b/src/typings.ts index a052f78c..6efc54d2 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -10,7 +10,7 @@ import { OverridableComponent } from '@mui/material/OverridableComponent'; import { SvgIconTypeMap } from '@mui/material/SvgIcon/SvgIcon'; import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; -import { ExtensionType } from '@/lib/graphql/generated/graphql.ts'; +import { ExtensionType, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; type GenericLocation = Omit & { state?: State }; @@ -77,6 +77,8 @@ export type Metadata = { [key in Keys]: Values; }; +export type GqlMetaHolder = { meta?: MetaType[] }; + export type MetadataHolder = { meta?: Metadata; }; @@ -236,7 +238,7 @@ export interface IReaderProps { curPage: number; initialPage: number; settings: IReaderSettings; - manga: IMangaCard | IManga; + manga: MangaType; chapter: IChapter | IPartialChapter; nextChapter: () => void; prevChapter: () => void; diff --git a/src/util/metadata.ts b/src/util/metadata.ts index dd69538b..8ef3464d 100644 --- a/src/util/metadata.ts +++ b/src/util/metadata.ts @@ -6,21 +6,17 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { mutate } from 'swr'; import { AllowedMetadataValueTypes, AppMetadataKeys, - ICategory, - IManga, - IMangaCard, - IMangaChapter, + GqlMetaHolder, IMetadataMigration, Metadata, MetadataHolder, MetadataKeyValuePair, } from '@/typings'; -import requestManager, { RequestManager } from '@/lib/requests/RequestManager.ts'; -import { MetaType } from '@/lib/graphql/generated/graphql.ts'; +import requestManager from '@/lib/requests/RequestManager.ts'; +import { CategoryType, ChapterType, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; const APP_METADATA_KEY_PREFIX = 'webUI_'; @@ -118,6 +114,27 @@ const convertValueFromMetadata = { + if (!gqlMetadata) { + return undefined; + } + + const metadata: Metadata = {}; + gqlMetadata.forEach(({ key, value }) => { + metadata[key] = value; + }); + + return metadata; +}; + +export const convertToGqlMeta = (metadata?: Metadata): MetaType[] | undefined => { + if (!metadata) { + return undefined; + } + + return Object.entries(metadata).map(([key, value]) => ({ key, value })); +}; + const getAppMetadataFrom = (meta: Metadata, appPrefix: string = APP_METADATA_KEY_PREFIX): Metadata => { const appMetadata: Metadata = {}; @@ -277,6 +294,8 @@ export const getMetadataFrom = { if (wrap) { return { @@ -294,85 +313,54 @@ const wrapMetadataWithMetaKey = (wrap: boolean, metadata: Metadata): MetadataHol type MetadataHolderType = 'manga' | 'chapter' | 'category' | 'global'; export const requestUpdateMetadataValue = async ( - metadataHolder: MetadataHolder, + metadataHolder: GqlMetaHolder, holderType: MetadataHolderType, key: AppMetadataKeys, value: AllowedMetadataValueTypes, ): Promise => { const metadataKey = getMetadataKey(key); - const mutatedMetadata = { - ...metadataHolder.meta, - [metadataKey]: `${value}`, - }; - let endpoint: string; switch (holderType) { case 'category': - endpoint = `category/${(metadataHolder as ICategory).id}/meta`; - await requestManager.setCategoryMeta((metadataHolder as ICategory).id, metadataKey, value).response; + await requestManager.setCategoryMeta((metadataHolder as CategoryType).id, metadataKey, value).response; break; case 'chapter': - // eslint-disable-next-line no-case-declarations - const { manga, chapter } = metadataHolder as IMangaChapter; - endpoint = `manga/${manga.id}/chapter/${chapter.index}/meta`; - await requestManager.setChapterMeta(chapter.id, metadataKey, value).response; + await requestManager.setChapterMeta((metadataHolder as ChapterType).id, metadataKey, value).response; break; case 'global': - endpoint = 'meta'; await requestManager.setGlobalMetadata(metadataKey, value).response; break; case 'manga': - endpoint = `manga/${(metadataHolder as IManga).id}/meta`; - await requestManager.setMangaMeta((metadataHolder as IManga).id, metadataKey, value).response; + await requestManager.setMangaMeta((metadataHolder as MangaType).id, metadataKey, value).response; break; default: throw new Error(`requestUpdateMetadataValue: unknown holderType "${holderType}"`); } - - const urlToMutate = `${RequestManager.API_VERSION}${endpoint}`; - mutate( - urlToMutate, - { ...metadataHolder, ...wrapMetadataWithMetaKey(holderType !== 'global', mutatedMetadata) }, - { revalidate: false }, - ); }; export const requestUpdateMetadata = async ( - metadataHolder: MetadataHolder, + metadataHolder: GqlMetaHolder, holderType: MetadataHolderType, keysToValues: [AppMetadataKeys, AllowedMetadataValueTypes][], ): Promise => Promise.all(keysToValues.map(([key, value]) => requestUpdateMetadataValue(metadataHolder, holderType, key, value))); export const requestUpdateServerMetadata = async ( - serverMetadata: Metadata, + serverMetadata: MetaType[], keysToValues: MetadataKeyValuePair[], ): Promise => requestUpdateMetadata({ meta: serverMetadata }, 'global', keysToValues); export const requestUpdateMangaMetadata = async ( - manga: IMangaCard | IManga, + manga: MangaType, keysToValues: MetadataKeyValuePair[], ): Promise => requestUpdateMetadata(manga, 'manga', keysToValues); export const requestUpdateChapterMetadata = async ( - mangaChapter: IMangaChapter, + chapter: ChapterType, keysToValues: MetadataKeyValuePair[], -): Promise => requestUpdateMetadata(mangaChapter.chapter, 'chapter', keysToValues); +): Promise => requestUpdateMetadata(chapter, 'chapter', keysToValues); export const requestUpdateCategoryMetadata = async ( - category: ICategory, + category: CategoryType, keysToValues: MetadataKeyValuePair[], ): Promise => requestUpdateMetadata(category, 'category', keysToValues); - -export const convertGqlMetadata = (gqlMetadata?: MetaType[]): Metadata | undefined => { - if (!gqlMetadata) { - return undefined; - } - - const metadata: Metadata = {}; - gqlMetadata.forEach(({ key, value }) => { - metadata[key] = value; - }); - - return metadata; -}; diff --git a/src/util/readerSettings.ts b/src/util/readerSettings.ts index 9dce9c73..d3f05cc8 100644 --- a/src/util/readerSettings.ts +++ b/src/util/readerSettings.ts @@ -6,14 +6,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { IManga, Metadata, MetadataHolder, IReaderSettings, MetadataKeyValuePair } from '@/typings'; +import { Metadata, IReaderSettings, MetadataKeyValuePair, GqlMetaHolder } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { - convertGqlMetadata, + convertFromGqlMeta, getMetadataFrom, requestUpdateMangaMetadata, requestUpdateServerMetadata, } from '@/util/metadata'; +import { MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; type UndefinedReaderSettings = { [setting in keyof IReaderSettings]: IReaderSettings[setting] | undefined; @@ -42,10 +43,10 @@ export const getReaderSettingsFromMetadata = ( ): IReaderSettings => getReaderSettingsWithDefaultValueFallback(meta, defaultSettings, applyMetadataMigration); export const getReaderSettingsFor = ( - { meta }: MetadataHolder, + { meta }: GqlMetaHolder = {}, defaultSettings?: IReaderSettings, applyMetadataMigration?: boolean, -): IReaderSettings => getReaderSettingsFromMetadata(meta, defaultSettings, applyMetadataMigration); +): IReaderSettings => getReaderSettingsFromMetadata(convertFromGqlMeta(meta), defaultSettings, applyMetadataMigration); export const useDefaultReaderSettings = (): { metadata?: Metadata; @@ -53,7 +54,7 @@ export const useDefaultReaderSettings = (): { loading: boolean; } => { const { data, loading } = requestManager.useGetGlobalMeta(); - const metadata = convertGqlMetadata(data?.metas.nodes); + const metadata = convertFromGqlMeta(data?.metas.nodes); const settings = getReaderSettingsWithDefaultValueFallback(metadata); return { metadata, settings, loading }; @@ -67,11 +68,12 @@ export const useDefaultReaderSettings = (): { * @param defaultSettings */ export const checkAndHandleMissingStoredReaderSettings = async ( - metadataHolder: IManga | MetadataHolder, + metadataHolder: Required | MetaType[], metadataHolderType: 'manga' | 'server', defaultSettings: IReaderSettings, ): Promise => { - const meta = metadataHolder.meta ?? (metadataHolder as Metadata); + const getMeta = () => (Array.isArray(metadataHolder) ? metadataHolder : metadataHolder.meta); + const meta = convertFromGqlMeta(getMeta())!; const settingsToCheck = getReaderSettingsWithDefaultValueFallback( meta, { @@ -85,7 +87,7 @@ export const checkAndHandleMissingStoredReaderSettings = async ( }, false, ); - const newSettings = getReaderSettingsFor({ meta }, defaultSettings); + const newSettings = getReaderSettingsFor({ meta: getMeta() }, defaultSettings); const undefinedSettings = Object.entries(settingsToCheck).filter((setting) => setting[1] === undefined); @@ -101,9 +103,9 @@ export const checkAndHandleMissingStoredReaderSettings = async ( } if (metadataHolderType === 'manga') { - await requestUpdateMangaMetadata(metadataHolder as IManga, settingsToUpdate); + await requestUpdateMangaMetadata(metadataHolder as MangaType, settingsToUpdate); return; } - await requestUpdateServerMetadata(meta, settingsToUpdate); + await requestUpdateServerMetadata(metadataHolder as MetaType[], settingsToUpdate); }; diff --git a/src/util/searchSettings.ts b/src/util/searchSettings.ts index 18958d81..5b8a7fc9 100644 --- a/src/util/searchSettings.ts +++ b/src/util/searchSettings.ts @@ -8,7 +8,7 @@ import { Metadata, ISearchSettings } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; -import { convertGqlMetadata, getMetadataFrom } from '@/util/metadata'; +import { convertFromGqlMeta, getMetadataFrom } from '@/util/metadata'; export const getDefaultSettings = (): ISearchSettings => ({ ignoreFilters: false, @@ -25,7 +25,7 @@ export const useSearchSettings = (): { loading: boolean; } => { const { data, loading } = requestManager.useGetGlobalMeta(); - const metadata = convertGqlMetadata(data?.metas.nodes); + const metadata = convertFromGqlMeta(data?.metas.nodes); const settings = getSearchSettingsWithDefaultValueFallback(metadata); return { metadata, settings, loading }; From af9d49e5e99fa52a6534307f46ec5a630619c9d7 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:47:13 +0200 Subject: [PATCH 24/47] Use gql for "mangas" II - category mangas --- src/components/MangaCard.tsx | 7 ++--- src/components/MangaGrid.tsx | 8 +++--- src/components/library/LibraryMangaGrid.tsx | 30 +++++++++++---------- src/lib/requests/RequestManager.ts | 10 ++++--- src/screens/Library.tsx | 25 ++++++++++------- 5 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/components/MangaCard.tsx b/src/components/MangaCard.tsx index 892b1751..c6e07626 100644 --- a/src/components/MangaCard.tsx +++ b/src/components/MangaCard.tsx @@ -12,10 +12,10 @@ import Typography from '@mui/material/Typography'; import { Link } from 'react-router-dom'; import { Avatar, Box, CardContent, styled } from '@mui/material'; import { useTranslation } from 'react-i18next'; -import { IMangaCard } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { GridLayout, useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import SpinnerImage from '@/components/util/SpinnerImage'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const BottomGradient = styled('div')({ position: 'absolute', @@ -66,7 +66,7 @@ const BadgeContainer = styled('div')({ }); interface IProps { - manga: IMangaCard; + manga: MangaType; gridLayout?: GridLayout; inLibraryIndicator?: boolean; } @@ -75,10 +75,11 @@ const MangaCard = (props: IProps) => { const { t } = useTranslation(); const { - manga: { id, title, thumbnailUrl, downloadCount, unreadCount: unread, inLibrary }, + manga: { id, title, thumbnailUrl: tmpThumbnailUrl, downloadCount, unreadCount: unread, inLibrary }, gridLayout, inLibraryIndicator, } = props; + const thumbnailUrl = tmpThumbnailUrl ?? 'nonExistingMangaUrl'; const { options: { showUnreadBadge, showDownloadBadge }, } = useLibraryOptionsContext(); diff --git a/src/components/MangaGrid.tsx b/src/components/MangaGrid.tsx index 1cabeb33..6051ff4f 100644 --- a/src/components/MangaGrid.tsx +++ b/src/components/MangaGrid.tsx @@ -11,12 +11,12 @@ import Grid, { GridTypeMap } from '@mui/material/Grid'; import { Box, Typography } from '@mui/material'; import { GridItemProps, VirtuosoGrid, VirtuosoGridHandle } from 'react-virtuoso'; import { useNavigate, useLocation } from 'react-router-dom'; -import { IMangaCard } from '@/typings'; import EmptyView from '@/components/util/EmptyView'; import LoadingPlaceholder from '@/components/util/LoadingPlaceholder'; import MangaCard from '@/components/MangaCard'; import { GridLayout } from '@/components/context/LibraryOptionsContext'; import useLocalStorage from '@/util/useLocalStorage'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const GridContainer = React.forwardRef(({ children, ...props }, ref) => ( @@ -40,13 +40,13 @@ const GridItemContainerWithDimension = ( ); }; -const createMangaCard = (manga: IMangaCard, gridLayout?: GridLayout, inLibraryIndicator?: boolean) => ( +const createMangaCard = (manga: MangaType, gridLayout?: GridLayout, inLibraryIndicator?: boolean) => ( ); type DefaultGridProps = { isLoading: boolean; - mangas: IMangaCard[]; + mangas: MangaType[]; inLibraryIndicator?: boolean; GridItemContainer: (props: GridTypeMap['props'] & Partial) => JSX.Element; gridLayout?: GridLayout; @@ -150,7 +150,7 @@ const VerticalGrid = ({ }; export interface IMangaGridProps { - mangas: IMangaCard[]; + mangas: MangaType[]; isLoading: boolean; message?: string; messageExtra?: JSX.Element; diff --git a/src/components/library/LibraryMangaGrid.tsx b/src/components/library/LibraryMangaGrid.tsx index c3250e05..321f0ec6 100644 --- a/src/components/library/LibraryMangaGrid.tsx +++ b/src/components/library/LibraryMangaGrid.tsx @@ -9,12 +9,13 @@ import React, { useEffect, useMemo } from 'react'; import { StringParam, useQueryParam } from 'use-query-params'; import { useTranslation } from 'react-i18next'; -import { IMangaCard, LibrarySortMode, NullAndUndefined } from '@/typings'; +import { LibrarySortMode, NullAndUndefined } from '@/typings'; import { useSearchSettings } from '@/util/searchSettings'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import MangaGrid from '@/components/MangaGrid'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; -const unreadFilter = (unread: NullAndUndefined, { unreadCount }: IMangaCard): boolean => { +const unreadFilter = (unread: NullAndUndefined, { unreadCount }: MangaType): boolean => { switch (unread) { case true: return !!unreadCount && unreadCount >= 1; @@ -25,7 +26,7 @@ const unreadFilter = (unread: NullAndUndefined, { unreadCount }: IManga } }; -const downloadedFilter = (downloaded: NullAndUndefined, { downloadCount }: IMangaCard): boolean => { +const downloadedFilter = (downloaded: NullAndUndefined, { downloadCount }: MangaType): boolean => { switch (downloaded) { case true: return !!downloadCount && downloadCount >= 1; @@ -36,24 +37,24 @@ const downloadedFilter = (downloaded: NullAndUndefined, { downloadCount } }; -const queryFilter = (query: NullAndUndefined, { title }: IMangaCard): boolean => { +const queryFilter = (query: NullAndUndefined, { title }: MangaType): boolean => { if (!query) return true; return title.toLowerCase().includes(query.toLowerCase()); }; -const queryGenreFilter = (query: NullAndUndefined, { genre }: IMangaCard): boolean => { +const queryGenreFilter = (query: NullAndUndefined, { genre }: MangaType): boolean => { if (!query) return true; const queries = query.split(',').map((str) => str.toLowerCase().trim()); return queries.every((element) => genre.map((el) => el.toLowerCase()).includes(element)); }; const filterManga = ( - mangas: IMangaCard[], + mangas: MangaType[], query: NullAndUndefined, unread: NullAndUndefined, downloaded: NullAndUndefined, ignoreFilters: boolean, -): IMangaCard[] => +): MangaType[] => mangas.filter((manga) => { const ignoreFiltersWhileSearching = ignoreFilters && query?.length; const matchesSearch = queryFilter(query, manga) || queryGenreFilter(query, manga); @@ -63,19 +64,20 @@ const filterManga = ( return matchesSearch && matchesFilters; }); -const sortByUnread = (a: IMangaCard, b: IMangaCard): number => (a.unreadCount ?? 0) - (b.unreadCount ?? 0); +const sortByUnread = (a: MangaType, b: MangaType): number => (a.unreadCount ?? 0) - (b.unreadCount ?? 0); -const sortByTitle = (a: IMangaCard, b: IMangaCard): number => a.title.localeCompare(b.title); +const sortByTitle = (a: MangaType, b: MangaType): number => a.title.localeCompare(b.title); -const sortByDateAdded = (a: IMangaCard, b: IMangaCard): number => a.inLibraryAt - b.inLibraryAt; +const sortByDateAdded = (a: MangaType, b: MangaType): number => Number(a.inLibraryAt) - Number(b.inLibraryAt); -const sortByLastRead = (a: IMangaCard, b: IMangaCard): number => b.lastReadAt - a.lastReadAt; +const sortByLastRead = (a: MangaType, b: MangaType): number => + Number(b.lastReadChapter?.lastReadAt ?? 0) - Number(a.lastReadChapter?.lastReadAt ?? 0); const sortManga = ( - manga: IMangaCard[], + manga: MangaType[], sort: NullAndUndefined, desc: NullAndUndefined, -): IMangaCard[] => { +): MangaType[] => { const result = [...manga]; switch (sort) { @@ -103,7 +105,7 @@ const sortManga = ( }; interface LibraryMangaGridProps { - mangas: IMangaCard[]; + mangas: MangaType[]; isLoading: boolean; message?: string; } diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 118b76a6..4bbdc403 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -25,7 +25,6 @@ import { BackupValidationResult, ICategory, IChapter, - IManga, IMangaChapter, ISourceFilters, PaginatedList, @@ -65,6 +64,8 @@ import { GetExtensionsFetchMutationVariables, GetCategoriesQuery, GetCategoriesQueryVariables, + GetCategoryMangasQuery, + GetCategoryMangasQueryVariables, GetExtensionsQuery, GetExtensionsQueryVariables, GetGlobalMetadatasQuery, @@ -918,8 +919,11 @@ export class RequestManager { ); } - public useGetCategoryMangas(categoryId: number, swrOptions?: SWROptions): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `category/${categoryId}`, { swrOptions }); + public useGetCategoryMangas( + id: number, + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequestNew(GQLMethod.USE_QUERY, GET_CATEGORY_MANGAS, { id }, options); } public deleteCategory(categoryId: number): AbortableApolloMutationResponse { diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index ecaf4279..dd11d669 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -20,6 +20,7 @@ import LibraryMangaGrid from '@/components/library/LibraryMangaGrid'; import AppbarSearch from '@/components/util/AppbarSearch'; import UpdateChecker from '@/components/library/UpdateChecker'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const StyledGridWrapper = styled(Box)(({ theme }) => ({ // TabsMenu height + TabsMenu bottom padding - grid item top padding @@ -63,8 +64,14 @@ export default function Library() { const { options } = useLibraryOptionsContext(); const [lastLibraryUpdate, setLastLibraryUpdate] = useState(Date.now()); - const { data, error: tabsError, loading: areCategoriesLoading } = requestManager.useGetCategories(); - const tabsData = data?.categories.nodes.filter((category) => category.id !== 0); + const { + data: categoriesResponse, + error: tabsError, + loading: areCategoriesLoading, + } = requestManager.useGetCategories(); + const tabsData = categoriesResponse?.categories.nodes.filter( + (category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount), + ); const tabs = tabsData ?? []; const librarySize = useMemo( () => tabs.map((tab) => tab.mangas.totalCount).reduce((prev, curr) => prev + curr, 0), @@ -75,11 +82,11 @@ export default function Library() { const activeTab = tabs.find((tab) => tab.order === tabSearchParam) ?? tabs[0]; const { - data: mangaData, + data: categoryMangaResponse, error: mangaError, - isLoading: mangaLoading, - } = requestManager.useGetCategoryMangas(activeTab?.id, { skipRequest: !activeTab }); - const mangas = mangaData ?? []; + loading: mangaLoading, + } = requestManager.useGetCategoryMangas(activeTab?.id, { skip: !activeTab }); + const mangas = (categoryMangaResponse?.category.mangas.nodes as unknown as MangaType[]) ?? []; const { setTitle, setAction } = useContext(NavbarContext); useEffect(() => { @@ -105,14 +112,14 @@ export default function Library() { }, [t, librarySize, areCategoriesLoading, options]); const handleTabChange = (newTab: number) => { - setTabSearchParam(newTab === 0 ? undefined : newTab); + setTabSearchParam(newTab); }; if (tabsError != null) { return ( ); } @@ -171,7 +178,7 @@ export default function Library() { (mangaError ? ( ) : ( Date: Fri, 8 Sep 2023 00:06:24 +0200 Subject: [PATCH 25/47] Use gql for "mangas" III - global search --- src/components/source/SourceMangaGrid.tsx | 4 +- src/lib/graphql/mutations/SourceMutation.ts | 6 +- src/lib/requests/RequestManager.ts | 130 +++++++++++++++++--- src/screens/SearchAll.tsx | 17 +-- src/typings.ts | 8 ++ 5 files changed, 138 insertions(+), 27 deletions(-) diff --git a/src/components/source/SourceMangaGrid.tsx b/src/components/source/SourceMangaGrid.tsx index 2b4f7b36..9b6cb7a8 100644 --- a/src/components/source/SourceMangaGrid.tsx +++ b/src/components/source/SourceMangaGrid.tsx @@ -7,10 +7,10 @@ */ import { useTranslation } from 'react-i18next'; -import { IMangaCard } from '@/typings'; import MangaGrid, { IMangaGridProps } from '@/components/MangaGrid'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; -function filterManga(mangas: IMangaCard[]): IMangaCard[] { +function filterManga(mangas: MangaType[]): MangaType[] { return mangas; } diff --git a/src/lib/graphql/mutations/SourceMutation.ts b/src/lib/graphql/mutations/SourceMutation.ts index f8a8a1e3..c258d812 100644 --- a/src/lib/graphql/mutations/SourceMutation.ts +++ b/src/lib/graphql/mutations/SourceMutation.ts @@ -7,16 +7,16 @@ */ import gql from 'graphql-tag'; -import { FULL_MANGA_FIELDS, FULL_SOURCE_FIELDS } from '@/lib/graphql/Fragments'; +import { BASE_MANGA_FIELDS, FULL_SOURCE_FIELDS } from '@/lib/graphql/Fragments'; export const GET_SOURCE_MANGAS_FETCH = gql` - ${FULL_MANGA_FIELDS} + ${BASE_MANGA_FIELDS} mutation GET_SOURCE_MANGAS_FETCH($input: FetchSourceMangaInput!) { fetchSourceManga(input: $input) { clientMutationId hasNextPage mangas { - ...FULL_MANGA_FIELDS + ...BASE_MANGA_FIELDS } } } diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 4bbdc403..46fa9421 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -21,6 +21,7 @@ import { useQuery, } from '@apollo/client'; import { OperationVariables } from '@apollo/client/core'; +import { useState } from 'react'; import { BackupValidationResult, ICategory, @@ -58,6 +59,9 @@ import { EnqueueChapterDownloadMutationVariables, EnqueueChapterDownloadsMutation, EnqueueChapterDownloadsMutationVariables, + FetchSourceMangaInput, + FetchSourceMangaType, + FilterChangeInput, GetAboutQuery, GetAboutQueryVariables, GetExtensionsFetchMutation, @@ -74,6 +78,8 @@ import { GetMangaFetchMutationVariables, GetMangaQuery, GetMangaQueryVariables, + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables, GetSourceQuery, GetSourceQueryVariables, GetSourcesQuery, @@ -214,6 +220,13 @@ type AbortableApolloUseMutationResponse[0], MutationTuple[1] & AbortableRequest, ]; +type AbortableApolloUseMutationPaginatedResponse< + Data = any, + Variables extends OperationVariables = OperationVariables, +> = [ + (page: number) => Promise>, + (MutationTuple[1] & AbortableRequest & { size: number; loadingMore: boolean })[], +]; type AbortableApolloMutationResponse = { response: Promise> } & AbortableRequest; const isLoadingMore = (swrResult: SWRInfiniteResponse): boolean => { @@ -625,6 +638,99 @@ export class RequestManager { return this.doRequestNew(GQLMethod.USE_QUERY, GET_SOURCE, { id }, options); } + public useGetSourceMangas( + input: FetchSourceMangaInput, + options?: MutationHookOptions, + ): AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + > { + const createPaginatedResult = ( + result: AbortableApolloUseMutationResponse[1], + page: number, + ): AbortableApolloUseMutationPaginatedResponse[1][number] => { + const loading = result.loading || !result.called; + return { + ...result, + loading, + size: page, + loadingMore: loading && page > 1, + }; + }; + + // TODO - implement caching + // - ? global cache with revalidating (same as SWR does, revalidate each page starting with 1st until the first page is reached whose data didn't change) + // - ? saving fetched mangas in location state and only "cache" when navigating prev/next + const [mutate, result] = this.doRequestNew( + GQLMethod.USE_MUTATION, + GET_SOURCE_MANGAS_FETCH, + { input }, + options, + ); + + const [previousResults, setPreviousResults] = useState([ + createPaginatedResult(result, input.page), + ]); + + const [contentType, setContentType] = useState(input.type); + const [query, setQuery] = useState(input.query); + const [page, setPage] = useState(input.page); + + const paginatedResult = createPaginatedResult(result, page); + + // TODO - option "global cache with revalidating" + // replace previousResults with cache + // cache specific response + // cache "base" key to specific page keys to be able to retrieve all necessary cached pages + // get cached results + // revalidate in background - revalidate first page -> result changed? revalidate every page until cached result and response is the same + + // wrap "mutate" function to align with the expected type, which allows only passing a "page" argument + const wrappedMutate = (newPage: number) => { + const resetPreviousResultForInitialLoad = newPage < page; + if (resetPreviousResultForInitialLoad) { + setPreviousResults(previousResults.filter((prevResult) => prevResult.size <= newPage)); + } + + if (newPage !== page) { + setPage(newPage); + } + + return mutate({ + variables: { + input: { + ...input, + page: newPage, + }, + }, + }); + }; + + const contentTypeChanged = contentType !== input.type; + const queryChanged = query !== input.query; + // instantly return empty results in case the provided variables changed - wait until the hook returns empty data, + // otherwise, updating the previous results will revert the reset + const resetPreviousResult = (queryChanged || contentTypeChanged) && !paginatedResult.data; + let updatedResults = [ + ...(resetPreviousResult ? [{ ...paginatedResult, size: page, loadingMore: false }] : previousResults), + ]; + + if (resetPreviousResult) { + setContentType(input.type); + setQuery(input.query); + setPreviousResults([paginatedResult]); + } + + const resultChanged = previousResults[page - 1]?.loading !== paginatedResult.loading; + const updatePreviousResult = resultChanged && !resetPreviousResult; + if (updatePreviousResult) { + updatedResults = [...previousResults.slice(0, page - 1), paginatedResult]; + setPreviousResults(updatedResults); + } + + return [wrappedMutate, updatedResult]; + } + public useGetSourcePopularMangas( sourceId: string, initialPages?: number, @@ -683,21 +789,15 @@ export class RequestManager { } public useSourceSearch( - sourceId: string, - searchTerm: string, - initialPages?: number, - swrOptions?: SWRInfiniteOptions, - ): AbortableSWRInfiniteResponse { - return this.doRequest(HttpMethod.SWR_GET_INFINITE, '', { - swrOptions: { - getEndpoint: (page, previousData) => - previousData?.hasNextPage ?? true - ? `source/${sourceId}/search?searchTerm=${searchTerm}&pageNum=${page + 1}` - : null, - initialSize: initialPages, - ...swrOptions, - } as typeof swrOptions, - }); + source: string, + query: string, + filters?: FilterChangeInput[], + options?: MutationHookOptions, + ): AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + > { + return this.useGetSourceMangas({ type: FetchSourceMangaType.Search, source, query, filters, page: 1 }, options); } public useSourceQuickSearch( diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index 1a337a30..1cc6bbd0 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -21,6 +21,7 @@ import LangSelect from '@/components/navbar/action/LangSelect'; import MangaGrid from '@/components/MangaGrid'; import NavbarContext from '@/components/context/NavbarContext'; import { useDebounce } from '@/components/manga/hooks'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean }; type SourceToLoadingStateMap = Map; @@ -99,15 +100,17 @@ const SourceSearchPreview = React.memo( const skipRequest = !searchString; const { id, displayName, lang } = source; - const { - data: searchResult, - isLoading, - error, - abortRequest, - } = requestManager.useSourceQuickSearch(id, searchString ?? '', [], 1, { skipRequest }); - const mangas = !isLoading ? searchResult?.[0]?.mangaList ?? [] : []; + const [loadPage, results] = requestManager.useSourceSearch(id, searchString ?? '', []); + const { data: searchResult, loading: isLoading, error, abortRequest } = results[0]!; + const mangas = (searchResult?.fetchSourceManga.mangas as MangaType[]) ?? []; const noMangasFound = !isLoading && !mangas.length; + useEffect(() => { + if (!skipRequest) { + loadPage(1); + } + }, [skipRequest, searchString]); + useEffect(() => { onSearchRequestFinished(source, isLoading, !noMangasFound, !searchString); }, [isLoading, noMangasFound, searchString]); diff --git a/src/typings.ts b/src/typings.ts index 6efc54d2..fc08e7ae 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -12,6 +12,14 @@ import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; import { ExtensionType, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; +export type RecursivePartial = { + [P in keyof T]?: T[P] extends (infer U)[] + ? RecursivePartial[] + : T[P] extends object | undefined + ? RecursivePartial + : T[P]; +}; + type GenericLocation = Omit & { state?: State }; declare module 'react-router-dom' { From 87aef85683a680969fc0999a431c09fd21707e06 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 12 Sep 2023 02:36:11 +0200 Subject: [PATCH 26/47] Use gql for "mangas" IV - source mangas popular/latest --- src/lib/requests/CustomCache.ts | 40 ++ src/lib/requests/RequestManager.ts | 670 ++++++++++++++++++++++++----- src/screens/SearchAll.tsx | 13 +- src/screens/SourceMangas.tsx | 147 ++++--- 4 files changed, 692 insertions(+), 178 deletions(-) create mode 100644 src/lib/requests/CustomCache.ts diff --git a/src/lib/requests/CustomCache.ts b/src/lib/requests/CustomCache.ts new file mode 100644 index 00000000..17679218 --- /dev/null +++ b/src/lib/requests/CustomCache.ts @@ -0,0 +1,40 @@ +/* + * Copyright (C) Contributors to the Suwayomi project + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// eslint-disable-next-line import/prefer-default-export +export class CustomCache { + private keyToResponseMap = new Map(); + + private keyToFetchTimestampMap = new Map(); + + public readonly createKeyFn = (endpoint: string, data: unknown): string => `${endpoint}_${JSON.stringify(data)}`; + + constructor(createKeyFn?: (endpoint: string, data: unknown) => string) { + this.createKeyFn = createKeyFn ?? this.createKeyFn; + } + + public getKeyFor(key: string, data: unknown): string { + return this.createKeyFn(key, data); + } + + public cacheResponse(endpoint: string, data: unknown, response: unknown) { + const createdKey = this.getKeyFor(endpoint, data); + this.keyToFetchTimestampMap.set(createdKey, Date.now()); + this.keyToResponseMap.set(createdKey, response); + } + + public getFetchTimestampFor(endpoint: string, data: unknown): number | undefined { + const key = this.getKeyFor(endpoint, data); + return this.keyToFetchTimestampMap.get(key); + } + + public getResponseFor(endpoint: string, data: unknown): Response | undefined { + const key = this.getKeyFor(endpoint, data); + return this.keyToResponseMap.get(key) as Response; + } +} diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 46fa9421..48a8682d 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -10,6 +10,8 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios'; import useSWR, { Middleware, SWRConfiguration, SWRResponse } from 'swr'; import useSWRInfinite, { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite'; import { + ApolloError, + DocumentNode, FetchResult, MutationHookOptions, MutationOptions, @@ -21,7 +23,7 @@ import { useQuery, } from '@apollo/client'; import { OperationVariables } from '@apollo/client/core'; -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { BackupValidationResult, ICategory, @@ -29,7 +31,6 @@ import { IMangaChapter, ISourceFilters, PaginatedList, - PaginatedMangaList, SourcePreferences, SourceSearchResult, } from '@/typings.ts'; @@ -173,6 +174,7 @@ import { UPDATE_LIBRARY_MANGAS, } from '@/lib/graphql/mutations/UpdaterMutation.ts'; import { GET_UPDATE_STATUS } from '@/lib/graphql/queries/UpdaterQuery.ts'; +import { CustomCache } from '@/lib/requests/CustomCache.ts'; enum SWRHttpMethod { SWR_GET, @@ -205,6 +207,12 @@ type SWRInfiniteResponseLoadInfo = { isInitialLoad: boolean; isLoadMore: boolean; }; + +type ApolloPaginatedMutationOptions = MutationHookOptions< + Data, + Variables +> & { skipRequest?: boolean }; + type AbortableRequest = { abortRequest: AbortController['abort'] }; export type AbortableAxiosResponse = { response: Promise } & AbortableRequest; export type AbortableSWRResponse = SWRResponse & AbortableRequest; @@ -212,22 +220,38 @@ export type AbortableSWRInfiniteResponse = SWRInfiniteR AbortableRequest & SWRInfiniteResponseLoadInfo; -type AbortableApolloUseQueryResponse< +export type AbortableApolloUseQueryResponse< Data = any, Variables extends OperationVariables = OperationVariables, > = QueryResult & AbortableRequest; -type AbortableApolloUseMutationResponse = [ - MutationTuple[0], - MutationTuple[1] & AbortableRequest, -]; -type AbortableApolloUseMutationPaginatedResponse< +export type AbortableApolloUseMutationResponse< + Data = any, + Variables extends OperationVariables = OperationVariables, +> = [MutationTuple[0], MutationTuple[1] & AbortableRequest]; +export type AbortableApolloUseMutationPaginatedResponse< Data = any, Variables extends OperationVariables = OperationVariables, > = [ (page: number) => Promise>, - (MutationTuple[1] & AbortableRequest & { size: number; loadingMore: boolean })[], + (Omit[1], 'loading'> & + AbortableRequest & { + size: number; + /** + * Indicates whether any request is currently active. + * In case only "isLoading" is true, it means that it's the initial request + */ + isLoading: boolean; + /** + * Indicates if a next page is being fetched, which is not part of the initial pages + */ + isLoadingMore: boolean; + /** + * Indicates if the cached pages are currently getting revalidated + */ + isValidating: boolean; + })[], ]; -type AbortableApolloMutationResponse = { response: Promise> } & AbortableRequest; +export type AbortableApolloMutationResponse = { response: Promise> } & AbortableRequest; const isLoadingMore = (swrResult: SWRInfiniteResponse): boolean => { const isNextPageMissing = !!swrResult.data && typeof swrResult.data[swrResult.size - 1] === 'undefined'; @@ -266,6 +290,8 @@ export class RequestManager { private readonly restClient: RestClient = new RestClient(); + private readonly cache = new CustomCache(); + public getClient(): IRestClient { return this.restClient; } @@ -299,6 +325,339 @@ export class RequestManager { return `${this.getBaseUrl()}${apiVersion}${endpoint}`; } + private createAbortController(): { signal: AbortSignal } & AbortableRequest { + const abortController = new AbortController(); + const abortRequest = (reason?: any): void => { + if (!abortController.signal.aborted) { + abortController.abort(reason); + } + }; + + return { signal: abortController.signal, abortRequest }; + } + + private createPaginatedResult( + result: Partial | undefined | null, + defaultPage: number, + page?: number, + ): Result { + const isLoading = !result?.error && (result?.isLoading || !result?.called); + const size = page ?? result?.size ?? defaultPage; + return { + client: this.graphQLClient.client, + abortRequest: () => {}, + reset: () => {}, + called: false, + data: undefined, + error: undefined, + size, + isLoading, + isLoadingMore: isLoading && size > 1, + isValidating: !!result?.isValidating, + ...result, + } as Result; + } + + private async revalidatePage( + cacheResultsKey: string, + cachePagesKey: string, + getVariablesFor: (page: number) => Variables, + options: ApolloPaginatedMutationOptions | undefined, + checkIfCachedPageIsInvalid: ( + cachedResult: AbortableApolloUseMutationPaginatedResponse[1][number] | undefined, + revalidatedResult: FetchResult, + ) => boolean, + hasNextPage: (revalidatedResult: FetchResult) => boolean, + pageToRevalidate: number, + maxPage: number, + signal: AbortSignal, + ): Promise { + const { response: revalidationRequest } = this.doRequestNew( + GQLMethod.MUTATION, + GET_SOURCE_MANGAS_FETCH, + getVariablesFor(pageToRevalidate), + { + ...options, + context: { fetchOptions: { signal } }, + }, + ); + + const revalidationResponse = await revalidationRequest; + const cachedPageData = this.cache.getResponseFor< + AbortableApolloUseMutationPaginatedResponse[1][number] + >(cacheResultsKey, getVariablesFor(pageToRevalidate)); + + const isCachedPageInvalid = checkIfCachedPageIsInvalid(cachedPageData, revalidationResponse); + if (isCachedPageInvalid) { + this.cache.cacheResponse(cacheResultsKey, getVariablesFor(pageToRevalidate), revalidationResponse); + } + + if (!hasNextPage(revalidationResponse)) { + const currentCachedPages = this.cache.getResponseFor>(cachePagesKey, getVariablesFor(0))!; + this.cache.cacheResponse( + cachePagesKey, + getVariablesFor(0), + [...currentCachedPages].filter((cachedPage) => cachedPage <= pageToRevalidate), + ); + [...currentCachedPages] + .filter((cachedPage) => cachedPage > pageToRevalidate) + .forEach((cachedPage) => + this.cache.cacheResponse(cacheResultsKey, getVariablesFor(cachedPage), undefined), + ); + return; + } + + if (isCachedPageInvalid && pageToRevalidate < maxPage) { + await this.revalidatePage( + cacheResultsKey, + cachePagesKey, + getVariablesFor, + options, + checkIfCachedPageIsInvalid, + hasNextPage, + pageToRevalidate + 1, + maxPage, + signal, + ); + } + } + + private async revalidatePages( + activeRevalidationRef: + | [ForInput: Variables, Request: Promise, AbortRequest: AbortableRequest['abortRequest']] + | null, + setRevalidationDone: (isDone: boolean) => void, + setActiveRevalidation: ( + activeRevalidation: + | [ForInput: Variables, Request: Promise, AbortRequest: AbortableRequest['abortRequest']] + | null, + ) => void, + getVariablesFor: (page: number) => Variables, + setValidating: (isValidating: boolean) => void, + revalidatePage: (pageToRevalidate: number, maxPage: number, signal: AbortSignal) => Promise, + maxPage: number, + abortRequest: AbortableRequest['abortRequest'], + signal: AbortSignal, + ): Promise { + setRevalidationDone(true); + + const [currRevVars, currRevPromise, currRevAbortRequest] = activeRevalidationRef ?? []; + + const isActiveRevalidationForInput = JSON.stringify(currRevVars) === JSON.stringify(getVariablesFor(0)); + + setValidating(true); + + if (!isActiveRevalidationForInput) { + currRevAbortRequest?.(new Error('Abort revalidation for different input')); + } + + let revalidationPromise = currRevPromise; + if (!isActiveRevalidationForInput) { + revalidationPromise = revalidatePage(1, maxPage, signal); + setActiveRevalidation([getVariablesFor(0), revalidationPromise, abortRequest]); + } + + try { + await revalidationPromise; + setActiveRevalidation(null); + } catch (e) { + // ignore + } finally { + setValidating(false); + } + } + + private async fetchPaginatedMutationPage< + Data = any, + Variables extends OperationVariables = OperationVariables, + ResultIdInfo extends Record = any, + >( + getVariablesFor: (page: number) => Variables, + setAbortRequest: (abortRequest: AbortableRequest['abortRequest']) => void, + getResultIdInfo: () => ResultIdInfo, + createPaginatedResult: ( + result: Partial[1][number]>, + ) => AbortableApolloUseMutationPaginatedResponse[1][number], + setResult: ( + result: AbortableApolloUseMutationPaginatedResponse[1][number] & ResultIdInfo, + ) => void, + revalidate: ( + maxPage: number, + abortRequest: AbortableRequest['abortRequest'], + signal: AbortSignal, + ) => Promise, + options: ApolloPaginatedMutationOptions | undefined, + documentNode: DocumentNode, + cachePagesKey: string, + cacheResultsKey: string, + cachedPages: Set, + newPage: number, + ): Promise> { + const basePaginatedResult: Partial[1][number]> = { + size: newPage, + isLoading: false, + isLoadingMore: false, + called: true, + }; + + let response: FetchResult = {}; + try { + const { signal, abortRequest } = this.createAbortController(); + setAbortRequest(abortRequest); + + setResult({ + ...getResultIdInfo(), + ...createPaginatedResult({ isLoading: true, abortRequest, size: newPage, called: true }), + }); + + if (newPage !== 1 && cachedPages.size) { + await revalidate(newPage, abortRequest, signal); + } + + const { response: request } = this.doRequestNew( + GQLMethod.MUTATION, + documentNode, + getVariablesFor(newPage), + { ...options, context: { fetchOptions: { signal } } }, + ); + + response = await request; + + basePaginatedResult.data = response.data; + } catch (error: any) { + if (error instanceof ApolloError) { + basePaginatedResult.error = error; + } else { + basePaginatedResult.error = new ApolloError({ + errorMessage: error?.message ?? error.toString(), + extraInfo: error, + }); + } + } + + const fetchPaginatedResult = { + ...getResultIdInfo(), + ...createPaginatedResult(basePaginatedResult), + }; + + setResult(fetchPaginatedResult); + + const shouldCacheResult = !fetchPaginatedResult.error; + if (shouldCacheResult) { + const currentCachedPages = this.cache.getResponseFor>(cachePagesKey, getVariablesFor(0)) ?? []; + this.cache.cacheResponse(cachePagesKey, getVariablesFor(0), new Set([...currentCachedPages, newPage])); + this.cache.cacheResponse(cacheResultsKey, getVariablesFor(newPage), fetchPaginatedResult); + } + + return response; + } + + private fetchInitialPages( + options: ApolloPaginatedMutationOptions | undefined, + areFetchingInitialPages: boolean, + areInitialPagesFetched: boolean, + setRevalidationDone: (isDone: boolean) => void, + cacheInitialPagesKey: string, + getVariablesFor: (page: number) => Variables, + initialPages: number, + fetchPage: (page: number) => Promise>, + hasNextPage: (result: FetchResult) => boolean, + ): void { + const shouldFetchInitialPages = !options?.skipRequest && !areFetchingInitialPages && !areInitialPagesFetched; + if (shouldFetchInitialPages) { + setRevalidationDone(true); + this.cache.cacheResponse(cacheInitialPagesKey, getVariablesFor(0), true); + + const loadInitialPages = async (initialPage: number) => { + const areAllPagesFetched = initialPage > initialPages; + if (areAllPagesFetched) { + return; + } + + const pageResult = await fetchPage(initialPage); + + if (hasNextPage(pageResult)) { + await loadInitialPages(initialPage + 1); + } + }; + + loadInitialPages(1); + } + } + + private returnPaginatedMutationResult( + areInitialPagesFetched: boolean, + cachedResults: AbortableApolloUseMutationPaginatedResponse[1][number][], + getVariablesFor: (page: number) => Variables, + paginatedResult: AbortableApolloUseMutationPaginatedResponse[1][number], + fetchPage: (page: number) => Promise>, + hasCachedResult: boolean, + createPaginatedResult: ( + result: Partial[1][number]>, + ) => AbortableApolloUseMutationPaginatedResponse[1][number], + ): AbortableApolloUseMutationPaginatedResponse { + const doCachedResultsExist = areInitialPagesFetched && cachedResults.length; + if (!doCachedResultsExist) { + return [fetchPage, [paginatedResult]]; + } + + const areAllPagesCached = doCachedResultsExist && hasCachedResult; + if (!areAllPagesCached) { + return [fetchPage, [...cachedResults, paginatedResult]]; + } + + return [ + fetchPage, + [ + ...cachedResults.slice(0, cachedResults.length - 1), + createPaginatedResult({ + ...cachedResults[cachedResults.length - 1], + isValidating: paginatedResult.isValidating, + }), + ], + ]; + } + + private revalidateInitialPages( + isRevalidationDone: boolean, + cachedResultsLength: number, + cachedPages: Set, + setRevalidationDone: (isDone: boolean) => void, + getVariablesFor: (page: number) => Variables, + triggerRerender: () => void, + revalidate: ( + maxPage: number, + abortRequest: AbortableRequest['abortRequest'], + signal: AbortSignal, + ) => Promise, + ): void { + const isMountedRef = useRef(false); + + useEffect(() => { + const isRevalidationRequired = isMountedRef.current && cachedResultsLength; + if (!isRevalidationRequired) { + return; + } + + setRevalidationDone(false); + triggerRerender(); + }, [JSON.stringify(getVariablesFor(0))]); + + useEffect(() => { + const shouldRevalidateData = isMountedRef.current && !isRevalidationDone && cachedResultsLength; + if (shouldRevalidateData) { + setRevalidationDone(true); + + const { signal, abortRequest } = this.createAbortController(); + revalidate(Math.max(...cachedPages), abortRequest, signal); + } + }, [isMountedRef.current, isRevalidationDone]); + + useEffect(() => { + isMountedRef.current = true; + }, []); + } + public getValidImgUrlFor(imageUrl: string, apiVersion: string = ''): string { const useCache = storage.getItem('useCache', true); const useCacheQuery = `?useCache=${useCache}`; @@ -339,13 +698,7 @@ export class RequestManager { | AbortableApolloUseQueryResponse | AbortableApolloUseMutationResponse | AbortableApolloMutationResponse { - const abortController = new AbortController(); - const abortRequest = (reason?: any): void => { - if (!abortController.signal.aborted) { - abortController.abort(reason); - } - }; - + const { signal, abortRequest } = this.createAbortController(); switch (method) { case GQLMethod.USE_QUERY: return { @@ -356,7 +709,7 @@ export class RequestManager { context: { ...options?.context, fetchOptions: { - signal: abortController.signal, + signal, ...options?.context?.fetchOptions, }, }, @@ -372,7 +725,7 @@ export class RequestManager { context: { ...options?.context, fetchOptions: { - signal: abortController.signal, + signal, ...options?.context?.fetchOptions, }, }, @@ -388,7 +741,7 @@ export class RequestManager { context: { ...options?.context, fetchOptions: { - signal: abortController.signal, + signal, ...options?.context?.fetchOptions, }, }, @@ -640,125 +993,209 @@ export class RequestManager { public useGetSourceMangas( input: FetchSourceMangaInput, - options?: MutationHookOptions, + initialPages: number = 1, + options?: ApolloPaginatedMutationOptions, ): AbortableApolloUseMutationPaginatedResponse< GetSourceMangasFetchMutation, GetSourceMangasFetchMutationVariables > { + type MutationResult = AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + >[1]; + type MutationDataResult = MutationResult[number]; + const createPaginatedResult = ( - result: AbortableApolloUseMutationResponse[1], - page: number, - ): AbortableApolloUseMutationPaginatedResponse[1][number] => { - const loading = result.loading || !result.called; - return { - ...result, - loading, - size: page, - loadingMore: loading && page > 1, - }; + result?: Partial | null, + page?: number, + ) => this.createPaginatedResult(result, input.page, page); + + const getVariablesFor = (page: number): GetSourceMangasFetchMutationVariables => ({ + input: { + ...input, + page, + }, + }); + + const CACHE_INITIAL_PAGES_FETCHING_KEY = 'GET_SOURCE_MANGAS_FETCH_FETCHING_INITIAL_PAGES'; + const CACHE_PAGES_KEY = 'GET_SOURCE_MANGAS_FETCH_PAGES'; + const CACHE_RESULTS_KEY = 'GET_SOURCE_MANGAS_FETCH'; + + const isRevalidationDoneRef = useRef(false); + const activeRevalidationRef = useRef< + | [ + ForInput: GetSourceMangasFetchMutationVariables, + Request: Promise, + AbortRequest: AbortableRequest['abortRequest'], + ] + | null + >(null); + const abortRequestRef = useRef(() => {}); + const resultRef = useRef<(MutationDataResult & { forInput: string }) | null>(null); + const result = resultRef.current; + + const [, setTriggerRerender] = useState(0); + const triggerRerender = () => setTriggerRerender((prev) => prev + 1); + const setResult = (nextResult: typeof resultRef.current) => { + resultRef.current = nextResult; + triggerRerender(); }; - // TODO - implement caching - // - ? global cache with revalidating (same as SWR does, revalidate each page starting with 1st until the first page is reached whose data didn't change) - // - ? saving fetched mangas in location state and only "cache" when navigating prev/next - const [mutate, result] = this.doRequestNew( - GQLMethod.USE_MUTATION, - GET_SOURCE_MANGAS_FETCH, - { input }, - options, + const cachedPages = this.cache.getResponseFor>(CACHE_PAGES_KEY, getVariablesFor(0)) ?? new Set(); + const cachedResults = [...cachedPages] + .map( + (cachedPage) => + this.cache.getResponseFor(CACHE_RESULTS_KEY, getVariablesFor(cachedPage))!, + ) + .sort((a, b) => a.size - b.size); + const areFetchingInitialPages = !!this.cache.getResponseFor( + CACHE_INITIAL_PAGES_FETCHING_KEY, + getVariablesFor(0), ); - const [previousResults, setPreviousResults] = useState([ - createPaginatedResult(result, input.page), - ]); + const areInitialPagesFetched = cachedResults.length >= initialPages; + const isResultForCurrentInput = result?.forInput === JSON.stringify(getVariablesFor(0)); + const lastPage = cachedPages.size ? Math.max(...cachedPages) : input.page; + const nextPage = isResultForCurrentInput ? result.size : lastPage; - const [contentType, setContentType] = useState(input.type); - const [query, setQuery] = useState(input.query); - const [page, setPage] = useState(input.page); + const paginatedResult = + isResultForCurrentInput && areInitialPagesFetched ? result : createPaginatedResult(undefined, nextPage); + paginatedResult.abortRequest = abortRequestRef.current; - const paginatedResult = createPaginatedResult(result, page); + // make sure that the result is always for the current input + resultRef.current = { forInput: JSON.stringify(getVariablesFor(0)), ...paginatedResult }; - // TODO - option "global cache with revalidating" - // replace previousResults with cache - // cache specific response - // cache "base" key to specific page keys to be able to retrieve all necessary cached pages - // get cached results - // revalidate in background - revalidate first page -> result changed? revalidate every page until cached result and response is the same + const hasCachedResult = !!this.cache.getResponseFor(CACHE_RESULTS_KEY, getVariablesFor(nextPage)); + + const revalidatePage = async (pageToRevalidate: number, maxPage: number, signal: AbortSignal) => + this.revalidatePage( + CACHE_RESULTS_KEY, + CACHE_PAGES_KEY, + getVariablesFor, + options, + (cachedResult, revalidatedResult) => + !cachedResult || + !cachedResult.data?.fetchSourceManga.mangas.length || + cachedResult.data.fetchSourceManga.mangas.some( + (manga, index) => manga.id !== revalidatedResult.data?.fetchSourceManga.mangas[index]?.id, + ), + (revalidatedResult) => !!revalidatedResult.data?.fetchSourceManga.hasNextPage, + pageToRevalidate, + maxPage, + signal, + ); + + const revalidate = async ( + maxPage: number, + abortRequest: AbortableRequest['abortRequest'], + signal: AbortSignal, + ) => + this.revalidatePages( + activeRevalidationRef.current, + (isDone) => { + isRevalidationDoneRef.current = isDone; + }, + (activeRevalidation) => { + activeRevalidationRef.current = activeRevalidation; + }, + getVariablesFor, + (isValidating) => { + setResult({ + ...createPaginatedResult(resultRef.current), + isValidating, + forInput: JSON.stringify(getVariablesFor(0)), + }); + }, + revalidatePage, + maxPage, + abortRequest, + signal, + ); // wrap "mutate" function to align with the expected type, which allows only passing a "page" argument - const wrappedMutate = (newPage: number) => { - const resetPreviousResultForInitialLoad = newPage < page; - if (resetPreviousResultForInitialLoad) { - setPreviousResults(previousResults.filter((prevResult) => prevResult.size <= newPage)); - } - - if (newPage !== page) { - setPage(newPage); - } - - return mutate({ - variables: { - input: { - ...input, - page: newPage, - }, + const wrappedMutate = async (newPage: number) => + this.fetchPaginatedMutationPage( + getVariablesFor, + (abortRequest) => { + abortRequestRef.current = abortRequest; }, - }); - }; + () => ({ forType: input.type, forQuery: input.query }), + createPaginatedResult, + setResult, + revalidate, + options, + GET_SOURCE_MANGAS_FETCH, + CACHE_PAGES_KEY, + CACHE_RESULTS_KEY, + cachedPages, + newPage, + ); - const contentTypeChanged = contentType !== input.type; - const queryChanged = query !== input.query; - // instantly return empty results in case the provided variables changed - wait until the hook returns empty data, - // otherwise, updating the previous results will revert the reset - const resetPreviousResult = (queryChanged || contentTypeChanged) && !paginatedResult.data; - let updatedResults = [ - ...(resetPreviousResult ? [{ ...paginatedResult, size: page, loadingMore: false }] : previousResults), - ]; + this.fetchInitialPages( + options, + areFetchingInitialPages, + areInitialPagesFetched, + (isDone) => { + isRevalidationDoneRef.current = isDone; + }, + CACHE_INITIAL_PAGES_FETCHING_KEY, + getVariablesFor, + initialPages, + wrappedMutate, + (fetchedResult) => !!fetchedResult.data?.fetchSourceManga.hasNextPage, + ); - if (resetPreviousResult) { - setContentType(input.type); - setQuery(input.query); - setPreviousResults([paginatedResult]); - } + this.revalidateInitialPages( + isRevalidationDoneRef.current, + cachedResults.length, + cachedPages, + (isDone) => { + isRevalidationDoneRef.current = isDone; + }, + getVariablesFor, + triggerRerender, + revalidate, + ); - const resultChanged = previousResults[page - 1]?.loading !== paginatedResult.loading; - const updatePreviousResult = resultChanged && !resetPreviousResult; - if (updatePreviousResult) { - updatedResults = [...previousResults.slice(0, page - 1), paginatedResult]; - setPreviousResults(updatedResults); - } - - return [wrappedMutate, updatedResult]; + return this.returnPaginatedMutationResult( + areInitialPagesFetched, + cachedResults, + getVariablesFor, + paginatedResult, + wrappedMutate, + hasCachedResult, + createPaginatedResult, + ); } public useGetSourcePopularMangas( sourceId: string, initialPages?: number, - swrOptions?: SWRInfiniteOptions, - ): AbortableSWRInfiniteResponse { - return this.doRequest(SWRHttpMethod.SWR_GET_INFINITE, '', { - swrOptions: { - getEndpoint: (page, previousData) => - previousData?.hasNextPage ?? true ? `source/${sourceId}/popular/${page + 1}` : null, - initialSize: initialPages, - ...swrOptions, - } as typeof swrOptions, - }); + options?: ApolloPaginatedMutationOptions, + ): AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + > { + return this.useGetSourceMangas( + { type: FetchSourceMangaType.Popular, source: sourceId, page: 1 }, + initialPages, + options, + ); } public useGetSourceLatestMangas( sourceId: string, initialPages?: number, - swrOptions?: SWRInfiniteOptions, - ): AbortableSWRInfiniteResponse { - return this.doRequest(SWRHttpMethod.SWR_GET_INFINITE, '', { - swrOptions: { - getEndpoint: (page, previousData) => - previousData?.hasNextPage ?? true ? `source/${sourceId}/latest/${page + 1}` : null, - initialSize: initialPages, - ...swrOptions, - } as typeof swrOptions, - }); + options?: ApolloPaginatedMutationOptions, + ): AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + > { + return this.useGetSourceMangas( + { type: FetchSourceMangaType.Latest, source: sourceId, page: 1 }, + initialPages, + options, + ); } public useGetSourcePreferences( @@ -790,14 +1227,19 @@ export class RequestManager { public useSourceSearch( source: string, - query: string, + query?: string, filters?: FilterChangeInput[], - options?: MutationHookOptions, + initialPages?: number, + options?: ApolloPaginatedMutationOptions, ): AbortableApolloUseMutationPaginatedResponse< GetSourceMangasFetchMutation, GetSourceMangasFetchMutationVariables > { - return this.useGetSourceMangas({ type: FetchSourceMangaType.Search, source, query, filters, page: 1 }, options); + return this.useGetSourceMangas( + { type: FetchSourceMangaType.Search, source, query, filters, page: 1 }, + initialPages, + options, + ); } public useSourceQuickSearch( diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index 1cc6bbd0..2afc5336 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -97,20 +97,15 @@ const SourceSearchPreview = React.memo( emptyQuery: boolean; }) => { const { t } = useTranslation(); - const skipRequest = !searchString; const { id, displayName, lang } = source; - const [loadPage, results] = requestManager.useSourceSearch(id, searchString ?? '', []); - const { data: searchResult, loading: isLoading, error, abortRequest } = results[0]!; + const [, results] = requestManager.useSourceSearch(id, searchString ?? '', undefined, 1, { + skipRequest: !searchString, + }); + const { data: searchResult, isLoading, error, abortRequest } = results[0]!; const mangas = (searchResult?.fetchSourceManga.mangas as MangaType[]) ?? []; const noMangasFound = !isLoading && !mangas.length; - useEffect(() => { - if (!skipRequest) { - loadPage(1); - } - }, [skipRequest, searchString]); - useEffect(() => { onSearchRequestFinished(source, isLoading, !noMangasFound, !searchString); }, [isLoading, noMangasFound, searchString]); diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index 038360b8..46d780ff 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -17,8 +17,8 @@ import { Box, Button, styled, useTheme, useMediaQuery } from '@mui/material'; import FavoriteIcon from '@mui/icons-material/Favorite'; import NewReleasesIcon from '@mui/icons-material/NewReleases'; import FilterListIcon from '@mui/icons-material/FilterList'; -import { IManga, PaginatedMangaList, TranslationKey } from '@/typings'; -import requestManager, { AbortableSWRInfiniteResponse } from '@/lib/requests/RequestManager.ts'; +import { TranslationKey } from '@/typings'; +import requestManager, { AbortableApolloUseMutationPaginatedResponse } from '@/lib/requests/RequestManager.ts'; import { useDebounce } from '@/components/manga/hooks'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import SourceGridLayout from '@/components/source/GridLayouts'; @@ -26,6 +26,11 @@ import AppbarSearch from '@/components/util/AppbarSearch'; import SourceOptions from '@/components/source/SourceOptions'; import NavbarContext from '@/components/context/NavbarContext'; import SourceMangaGrid from '@/components/source/SourceMangaGrid'; +import { + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables, + MangaType, +} from '@/lib/graphql/generated/graphql.ts'; const ContentTypeMenu = styled('div')(({ theme }) => ({ display: 'flex', @@ -81,15 +86,8 @@ const SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY: { [contentType in SourceContentType] [SourceContentType.SEARCH]: 'manga.error.label.no_mangas_found', }; -type SourceMangaResponse = Omit, 'data'> & { - data: { - items: IManga[]; - hasNextPage: boolean; - }; -}; - -const getUniqueMangas = (mangas: IManga[]): IManga[] => { - const uniqueMangas: IManga[] = []; +const getUniqueMangas = (mangas: MangaType[]): MangaType[] => { + const uniqueMangas: MangaType[] = []; mangas.forEach((manga) => { const isDuplicate = uniqueMangas.some((uniqueManga) => uniqueManga.id === manga.id); @@ -106,9 +104,18 @@ const useSourceManga = ( contentType: SourceContentType, searchTerm: string | null | undefined, filters: IPos[], - initialPages = 1, -): SourceMangaResponse => { - let result: AbortableSWRInfiniteResponse; + initialPages: number, +): [ + AbortableApolloUseMutationPaginatedResponse[0], + AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + >[1][number], +] => { + let result: AbortableApolloUseMutationPaginatedResponse< + GetSourceMangasFetchMutation, + GetSourceMangasFetchMutationVariables + >; switch (contentType) { case SourceContentType.POPULAR: result = requestManager.useGetSourcePopularMangas(sourceId, initialPages); @@ -117,45 +124,71 @@ const useSourceManga = ( result = requestManager.useGetSourceLatestMangas(sourceId, initialPages); break; case SourceContentType.SEARCH: - result = requestManager.useSourceQuickSearch(sourceId, searchTerm ?? '', [], initialPages); + result = requestManager.useSourceSearch(sourceId, searchTerm ?? '', undefined, initialPages); break; case SourceContentType.FILTER: - result = requestManager.useSourceQuickSearch( - sourceId, - '', - filters.map((filter) => { - const { position, state, group } = filter; - - const isPartOfGroup = group !== undefined; - if (isPartOfGroup) { - return { - position: group, - state: JSON.stringify({ - position, - state, - }), - }; - } - - return filter; - }), - initialPages, - { disableCache: true }, - ); + result = requestManager.useSourceSearch(sourceId, undefined, [], initialPages); + // TODO - update filters to gql + // result = requestManager.useSourceQuickSearch( + // sourceId, + // '', + // filters.map((filter) => { + // const { position, state, group } = filter; + // + // const isPartOfGroup = group !== undefined; + // if (isPartOfGroup) { + // return { + // position: group, + // state: JSON.stringify({ + // position, + // state, + // }), + // }; + // } + // + // return filter; + // }), + // initialPages, + // { disableCache: true }, + // ); break; default: throw new Error(`Unknown ContentType "${contentType}"`); } - const pages = result.data; - const { hasNextPage } = pages?.[pages.length - 1] ?? { hasNextPage: false }; + const pages = result[1]!; + const lastLoadedPageIndex = pages.findLastIndex((page) => !!page.data?.fetchSourceManga); + const lastLoadedPage = pages[lastLoadedPageIndex]; const items = useMemo( - () => (pages ?? []).map((page) => page.mangaList).reduce((prevList, list) => [...prevList, ...list], []), + () => + (pages ?? []) + .map((page) => page.data?.fetchSourceManga.mangas ?? []) + .reduce((prevList, list) => [...prevList, ...list], []), [pages], - ); + ) as MangaType[]; const uniqueItems = useMemo(() => getUniqueMangas(items), [items]); - return { ...result, data: { items: uniqueItems, hasNextPage } }; + if (!uniqueItems.length) { + return [result[0] as any, result[1][result[1].length - 1]]; + } + + return [ + result[0], + { + ...pages[pages.length - 1], + data: { + ...lastLoadedPage!.data, + fetchSourceManga: { + ...lastLoadedPage!.data!.fetchSourceManga, + hasNextPage: + pages.length > lastLoadedPageIndex + 1 + ? false + : lastLoadedPage!.data!.fetchSourceManga.hasNextPage, + mangas: uniqueItems, + }, + }, + }, + ]; }; export default function SourceMangas() { @@ -179,17 +212,19 @@ export default function SourceMangas() { const searchTerm = useDebounce(query, 1000); const [resetScrollPosition, setResetScrollPosition] = useState(false); const [contentType, setContentType] = useState(currentLocationContentType); - const { - data: { items: mangas, hasNextPage } = { items: [], hasNextPage: false }, - isLoading, - size: lastPageNum, - setSize: setPages, - mutate: refreshData, - abortRequest, - } = useSourceManga(sourceId, contentType, searchTerm, filtersToApply, isLargeScreen ? 2 : 1); + const [loadPage, { data, isLoading, size: lastPageNum, abortRequest }] = useSourceManga( + sourceId, + contentType, + searchTerm, + filtersToApply, + isLargeScreen ? 2 : 1, + ); + const mangas = (data?.fetchSourceManga.mangas as MangaType[]) ?? []; + const hasNextPage = data?.fetchSourceManga.hasNextPage ?? false; + const { data: filters = [], mutate: mutateFilters } = requestManager.useGetSourceFilters(sourceId); - const { data } = requestManager.useGetSource(sourceId); - const source = data?.source; + const { data: sourceData } = requestManager.useGetSource(sourceId); + const source = sourceData?.source; const [triggerDataRefresh, setTriggerDataRefresh] = useState(false); const message = !isLoading ? t(SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY[contentType]) : undefined; @@ -231,8 +266,8 @@ export default function SourceMangas() { return; } - setPages(lastPageNum + 1); - }, [setPages, lastPageNum, hasNextPage]); + loadPage(lastPageNum + 1); + }, [lastPageNum, hasNextPage, contentType]); const resetFilters = useCallback(async () => { setDialogFiltersToApply([]); @@ -262,12 +297,13 @@ export default function SourceMangas() { [searchTerm, contentType], ); + // TODO - check when fixing filters useEffect(() => { if (!triggerDataRefresh) { return; } - refreshData(); + // refreshData(); setTriggerDataRefresh(false); }, [triggerDataRefresh]); @@ -327,6 +363,7 @@ export default function SourceMangas() { Date: Sun, 24 Sep 2023 17:59:29 +0200 Subject: [PATCH 27/47] Use gql for "mangas" V - update manga categories --- src/components/navbar/action/CategorySelect.tsx | 6 +++--- src/lib/requests/RequestManager.ts | 8 -------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/components/navbar/action/CategorySelect.tsx b/src/components/navbar/action/CategorySelect.tsx index 7087fe63..be30cd52 100644 --- a/src/components/navbar/action/CategorySelect.tsx +++ b/src/components/navbar/action/CategorySelect.tsx @@ -29,7 +29,7 @@ export default function CategorySelect(props: IProps) { const { open, setOpen, mangaId } = props; - const { data: mangaCategoriesData, mutate } = requestManager.useGetMangaCategories(mangaId); + const { data: mangaResult } = requestManager.useGetManga(mangaId); const { data } = requestManager.useGetCategories(); const categoriesData = data?.categories.nodes; const [triggerMutate] = requestManager.useUpdateMangaCategories(); @@ -42,7 +42,7 @@ export default function CategorySelect(props: IProps) { return cats; }, [categoriesData]); - const selectedIds = mangaCategoriesData?.map((c) => c.id) ?? []; + const selectedIds = mangaResult?.manga.categories.nodes.map((c) => c.id) ?? []; const handleCancel = () => { setOpen(false); @@ -66,7 +66,7 @@ export default function CategorySelect(props: IProps) { }, }, }, - }).then(() => mutate()); + }); }; return ( diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 48a8682d..2c61c5d2 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -26,7 +26,6 @@ import { OperationVariables } from '@apollo/client/core'; import { useEffect, useRef, useState } from 'react'; import { BackupValidationResult, - ICategory, IChapter, IMangaChapter, ISourceFilters, @@ -1292,13 +1291,6 @@ export class RequestManager { return this.getValidImgUrlFor(`manga/${mangaId}/thumbnail`); } - public useGetMangaCategories( - mangaId: number, - swrOptions?: SWROptions, - ): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `manga/${mangaId}/category`, { swrOptions }); - } - public useUpdateMangaCategories( options?: MutationHookOptions, ): AbortableApolloUseMutationResponse { From 12dd973179e8599fd34782b7f958c09d9609343d Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:32:23 +0200 Subject: [PATCH 28/47] Use gql for "mangas" VI - source mangas filter --- src/components/source/SourceOptions.tsx | 76 ++++++++++--------- .../source/filters/CheckBoxFilter.tsx | 2 +- src/components/source/filters/GroupFilter.tsx | 9 ++- .../source/filters/SelectFilter.tsx | 64 +--------------- src/components/source/filters/SortFilter.tsx | 6 +- src/components/source/filters/TextFilter.tsx | 2 +- .../source/filters/TriStateFilter.tsx | 34 ++++++++- src/lib/requests/RequestManager.ts | 38 ---------- src/screens/SourceMangas.tsx | 71 +++++++---------- src/typings.ts | 26 +------ 10 files changed, 113 insertions(+), 215 deletions(-) diff --git a/src/components/source/SourceOptions.tsx b/src/components/source/SourceOptions.tsx index ec462b68..00f67678 100644 --- a/src/components/source/SourceOptions.tsx +++ b/src/components/source/SourceOptions.tsx @@ -10,7 +10,7 @@ import FilterListIcon from '@mui/icons-material/FilterList'; import { Button, Stack, Box } from '@mui/material'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ISourceFilters, IState } from '@/typings'; +import { SourceFilters } from '@/typings'; import OptionsPanel from '@/components/molecules/OptionsPanel'; import CheckBoxFilter from '@/components/source/filters/CheckBoxFilter'; import HeaderFilter from '@/components/source/filters/HeaderFilter'; @@ -25,14 +25,14 @@ import SeperatorFilter from '@/components/source/filters/SeparatorFilter'; import StyledFab from '@/components/util/StyledFab'; interface IFilters { - sourceFilter: ISourceFilters[]; + sourceFilter: SourceFilters[]; updateFilterValue: Function; group: number | undefined; update: any; } interface IFilters1 { - sourceFilter: ISourceFilters[]; + sourceFilter: SourceFilters[]; updateFilterValue: Function; resetFilterValue: Function; setTriggerUpdate: Function; @@ -42,85 +42,89 @@ interface IFilters1 { export function Options({ sourceFilter, group, updateFilterValue, update }: IFilters) { return ( - {sourceFilter.map((e: ISourceFilters, index) => { + {sourceFilter.map((e, index) => { let checkif = update.find( (el: { group: number | undefined; position: number }) => el.group === group && el.position === index, ); checkif = checkif ? checkif.state : checkif; switch (e.type) { - case 'CheckBox': + case 'CheckBoxFilter': return ( ); - case 'Group': + case 'GroupFilter': return ( ); - case 'Header': - return ; - case 'Select': + case 'HeaderFilter': + return ; + case 'SelectFilter': return ( ); - case 'Separator': - return ; - case 'Sort': + case 'SeparatorFilter': + return ; + case 'SortFilter': return ( ); - case 'Text': + case 'TextFilter': return ( ); - case 'TriState': + case 'TriStateFilter': return ( ); default: - return ; + throw new Error(`Unknown source filter "${e}"`); } })} diff --git a/src/components/source/filters/CheckBoxFilter.tsx b/src/components/source/filters/CheckBoxFilter.tsx index 125da405..8219ae71 100644 --- a/src/components/source/filters/CheckBoxFilter.tsx +++ b/src/components/source/filters/CheckBoxFilter.tsx @@ -27,7 +27,7 @@ const CheckBoxFilter: React.FC = (props: Props) => { const upd = update.filter( (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group), ); - updateFilterValue([...upd, { position, state: event.target.checked.toString(), group }]); + updateFilterValue([...upd, { type: 'checkBoxState', position, state: event.target.checked, group }]); }; if (state !== undefined) { diff --git a/src/components/source/filters/GroupFilter.tsx b/src/components/source/filters/GroupFilter.tsx index 2a4db407..f1cf7589 100644 --- a/src/components/source/filters/GroupFilter.tsx +++ b/src/components/source/filters/GroupFilter.tsx @@ -10,11 +10,14 @@ import { ExpandLess, ExpandMore } from '@mui/icons-material'; import { Collapse, ListItemButton, ListItemText, Stack, Box } from '@mui/material'; import React from 'react'; // eslint-disable-next-line import/no-cycle -import { ISourceFilters } from '@/typings'; +import { SourceFilters } from '@/typings'; import { Options } from '@/components/source/SourceOptions'; +// type ExcludeByName = T extends { __typename?: K } ? never : T; +type PickByName = T extends { __typename?: K } ? T : never; + interface Props { - state: ISourceFilters[]; + state: PickByName['filters']; name: string; position: number; updateFilterValue: Function; @@ -36,7 +39,7 @@ const GroupFilter: React.FC = (props: Props) => { {/* Container is moved outside 2, so content has to go inside 4 */} { - const vall = values.map((e) => e.displayname).indexOf(`${event.target.value}`); - setval(vall); - const upd = update.filter( - (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group), - ); - updateFilterValue([...upd, { position, state: vall.toString(), group }]); - }; - - const rett = values.map((e: Selected) => ( - - {e.displayname} - - )); - return ( - - {name} - - - ); - } - return null; -} - function noSelect( values: string[], name: string, @@ -84,7 +40,7 @@ function noSelect( const upd = update.filter( (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group), ); - updateFilterValue([...upd, { position, state: vall.toString(), group }]); + updateFilterValue([...upd, { type: 'selectState', position, state: vall, group }]); }; const rett = values.map((value: string) => ( @@ -104,21 +60,7 @@ function noSelect( return null; } -const SelectFilter: React.FC = ({ - values, - name, - state, - selected, - position, - updateFilterValue, - update, - group, -}) => { - if (selected === undefined) { - return noSelect(values, name, state, position, updateFilterValue, update, group); - } - - return hasSelect(values, name, state, position, updateFilterValue, update, group); -}; +const SelectFilter: React.FC = ({ values, name, state, position, updateFilterValue, update, group }) => + noSelect(values, name, state, position, updateFilterValue, update, group); export default SelectFilter; diff --git a/src/components/source/filters/SortFilter.tsx b/src/components/source/filters/SortFilter.tsx index beb4f6a3..4748cf29 100644 --- a/src/components/source/filters/SortFilter.tsx +++ b/src/components/source/filters/SortFilter.tsx @@ -9,13 +9,13 @@ import { ExpandLess, ExpandMore } from '@mui/icons-material'; import { Collapse, ListItemButton, ListItemText, Stack, Box } from '@mui/material'; import React from 'react'; -import { IState } from '@/typings'; import SortRadioInput from '@/components/atoms/SortRadioInput'; +import { SortSelectionInput } from '@/lib/graphql/generated/graphql.ts'; interface Props { values: any; name: string; - state: IState; + state: SortSelectionInput; position: number; group: number | undefined; updateFilterValue: Function; @@ -45,7 +45,7 @@ const SortFilter: React.FC = (props: Props) => { const upd = update.filter( (e: { position: number; group: number | undefined }) => !(position === e.position && group === e.group), ); - updateFilterValue([...upd, { position, state: JSON.stringify(tmp), group }]); + updateFilterValue([...upd, { type: 'sortState', position, state: tmp, group }]); }; return ( diff --git a/src/components/source/filters/TextFilter.tsx b/src/components/source/filters/TextFilter.tsx index 7dd82065..7b62304b 100644 --- a/src/components/source/filters/TextFilter.tsx +++ b/src/components/source/filters/TextFilter.tsx @@ -29,7 +29,7 @@ const TextFilter: React.FC = (props) => { const upd = update.filter( (el: { position: number; group: number | undefined }) => !(position === el.position && group === el.group), ); - updateFilterValue([...upd, { position, state: inputText, group }]); + updateFilterValue([...upd, { type: 'textState', position, state: inputText, group }]); }, [inputText]); if (state !== undefined) { diff --git a/src/components/source/filters/TriStateFilter.tsx b/src/components/source/filters/TriStateFilter.tsx index e9270b25..70a53094 100644 --- a/src/components/source/filters/TriStateFilter.tsx +++ b/src/components/source/filters/TriStateFilter.tsx @@ -8,9 +8,10 @@ import React from 'react'; import ThreeStateCheckboxInput from '@/components/atoms/ThreeStateCheckboxInput'; +import { TriState } from '@/lib/graphql/generated/graphql.ts'; interface Props { - state: number; + state: TriState; name: string; position: number; group: number | undefined; @@ -18,9 +19,35 @@ interface Props { update: any; } +const convertTriStateToNumber = (triState: TriState): number => { + switch (triState) { + case TriState.Ignore: + return 0; + case TriState.Include: + return 1; + case TriState.Exclude: + return 2; + default: + throw new Error(`Unexpected TriState ${triState}`); + } +}; + +const convertNumberToTriState = (state: number): TriState => { + switch (state) { + case 0: + return TriState.Ignore; + case 1: + return TriState.Include; + case 2: + return TriState.Exclude; + default: + throw new Error(`Unexpected state number ${state}`); + } +}; + const TriStateFilter: React.FC = (props) => { const { state, name, position, group, updateFilterValue, update } = props; - const [val, setval] = React.useState(Number(state)); + const [val, setval] = React.useState(convertTriStateToNumber(state)); const handleChange = (checked: boolean | null | undefined) => { // eslint-disable-next-line no-nested-ternary @@ -32,8 +59,9 @@ const TriStateFilter: React.FC = (props) => { updateFilterValue([ ...upd, { + type: 'triState', position, - state: newState.toString(), + state: convertNumberToTriState(newState), group, }, ]); diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 2c61c5d2..7721e253 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -28,10 +28,8 @@ import { BackupValidationResult, IChapter, IMangaChapter, - ISourceFilters, PaginatedList, SourcePreferences, - SourceSearchResult, } from '@/typings.ts'; import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; @@ -1208,22 +1206,6 @@ export class RequestManager { return this.doRequest(HttpMethod.POST, `source/${sourceId}/preferences`, { data: { position, value } }); } - public useGetSourceFilters( - sourceId: string, - reset?: boolean, - swrOptions?: SWROptions, - ): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `source/${sourceId}/filters`, { swrOptions }); - } - - public setSourceFilters(sourceId: string, filters: { position: number; state: string }[]): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, `source/${sourceId}/filters`, { data: filters }); - } - - public resetSourceFilters(sourceId: string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.GET, `source/${sourceId}/filters?reset=true`); - } - public useSourceSearch( source: string, query?: string, @@ -1241,26 +1223,6 @@ export class RequestManager { ); } - public useSourceQuickSearch( - sourceId: string, - searchTerm: string, - filters: { position: number; state: string }[], - initialPages?: number, - swrOptions?: SWRInfiniteOptions, - ): AbortableSWRInfiniteResponse { - return this.doRequest(HttpMethod.SWR_POST_INFINITE, '', { - data: { searchTerm, filter: filters }, - swrOptions: { - getEndpoint: (page, previousData) => - previousData?.hasNextPage ?? true - ? `source/${sourceId}/quick-search?searchTerm=${searchTerm}&pageNum=${page + 1}` - : null, - initialSize: initialPages, - ...swrOptions, - } as typeof swrOptions, - }); - } - public useGetManga( mangaId: number | string, options?: QueryHookOptions, diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index 46d780ff..f3e3d1c4 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -74,6 +74,7 @@ export enum SourceContentType { } interface IPos { + type: 'selectState' | 'textState' | 'checkBoxState' | 'triState' | 'sortState'; position: number; state: any; group?: number; @@ -127,30 +128,30 @@ const useSourceManga = ( result = requestManager.useSourceSearch(sourceId, searchTerm ?? '', undefined, initialPages); break; case SourceContentType.FILTER: - result = requestManager.useSourceSearch(sourceId, undefined, [], initialPages); - // TODO - update filters to gql - // result = requestManager.useSourceQuickSearch( - // sourceId, - // '', - // filters.map((filter) => { - // const { position, state, group } = filter; - // - // const isPartOfGroup = group !== undefined; - // if (isPartOfGroup) { - // return { - // position: group, - // state: JSON.stringify({ - // position, - // state, - // }), - // }; - // } - // - // return filter; - // }), - // initialPages, - // { disableCache: true }, - // ); + result = requestManager.useSourceSearch( + sourceId, + undefined, + filters.map((filter) => { + const { position, state, group } = filter; + + const isPartOfGroup = group !== undefined; + if (isPartOfGroup) { + return { + position: group, + groupChange: { + position, + [filter.type]: state, + }, + }; + } + + return { + position, + [filter.type]: state, + }; + }), + initialPages, + ); break; default: throw new Error(`Unknown ContentType "${contentType}"`); @@ -222,10 +223,9 @@ export default function SourceMangas() { const mangas = (data?.fetchSourceManga.mangas as MangaType[]) ?? []; const hasNextPage = data?.fetchSourceManga.hasNextPage ?? false; - const { data: filters = [], mutate: mutateFilters } = requestManager.useGetSourceFilters(sourceId); const { data: sourceData } = requestManager.useGetSource(sourceId); const source = sourceData?.source; - const [triggerDataRefresh, setTriggerDataRefresh] = useState(false); + const filters = source?.filters ?? []; const message = !isLoading ? t(SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY[contentType]) : undefined; const isLocalSource = sourceId === '0'; @@ -272,14 +272,6 @@ export default function SourceMangas() { const resetFilters = useCallback(async () => { setDialogFiltersToApply([]); setFiltersToApply([]); - try { - // required since previous implementation used to set the filters on server side (server caches them), thus, it has to be made sure that they are reset - await requestManager.resetSourceFilters(sourceId); - mutateFilters(); - } catch (error) { - // ignore - } - setTriggerDataRefresh(true); }, [sourceId]); useEffect( @@ -297,16 +289,6 @@ export default function SourceMangas() { [searchTerm, contentType], ); - // TODO - check when fixing filters - useEffect(() => { - if (!triggerDataRefresh) { - return; - } - - // refreshData(); - setTriggerDataRefresh(false); - }, [triggerDataRefresh]); - useEffect(() => { setTitle(source?.displayName ?? t('source.title')); setAction( @@ -378,7 +360,6 @@ export default function SourceMangas() { updateFilterValue={setDialogFiltersToApply} setTriggerUpdate={() => { setFiltersToApply(dialogFiltersToApply); - setTriggerDataRefresh(true); }} resetFilterValue={resetFilters} update={dialogFiltersToApply} diff --git a/src/typings.ts b/src/typings.ts index fc08e7ae..ca0669cc 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -10,7 +10,7 @@ import { OverridableComponent } from '@mui/material/OverridableComponent'; import { SvgIconTypeMap } from '@mui/material/SvgIcon/SvgIcon'; import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; -import { ExtensionType, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; +import { ExtensionType, GetSourceQuery, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; export type RecursivePartial = { [P in keyof T]?: T[P] extends (infer U)[] @@ -43,29 +43,7 @@ export interface ISource { displayName: string; } -export interface ISourceFilters { - type: string; - filter: ISourceFilter; -} - -export interface ISourceFilter { - name: string; - state: number | string | boolean | ISourceFilters[] | IState; - values?: string[]; - displayValues?: string[]; - selected?: ISelected; -} - -export interface ISelected { - displayname: string; - value: string; - _value: string; -} - -export interface IState { - ascending: boolean; - index: number; -} +export type SourceFilters = GetSourceQuery['source']['filters'][number]; export interface IMetadataMigration { appKeyPrefix?: { oldPrefix: string; newPrefix: string }; From dcead5a801cec5e7cba92ee5effb458a2940a6ba Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sun, 24 Sep 2023 22:34:37 +0200 Subject: [PATCH 29/47] Preserve selected filters on browser back navigation --- src/screens/SourceMangas.tsx | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/screens/SourceMangas.tsx b/src/screens/SourceMangas.tsx index f3e3d1c4..3db87ace 100644 --- a/src/screens/SourceMangas.tsx +++ b/src/screens/SourceMangas.tsx @@ -201,15 +201,19 @@ export default function SourceMangas() { const { sourceId } = useParams<{ sourceId: string }>(); const navigate = useNavigate(); - const { contentType: currentLocationContentType = SourceContentType.POPULAR } = + const { + contentType: currentLocationContentType = SourceContentType.POPULAR, + filtersToApply: currentLocationFiltersToApply = [], + } = useLocation<{ contentType: SourceContentType; + filtersToApply: IPos[]; }>().state ?? {}; const { options } = useLibraryOptionsContext(); const [query] = useQueryParam('query', StringParam); - const [dialogFiltersToApply, setDialogFiltersToApply] = useState([]); - const [filtersToApply, setFiltersToApply] = useState([]); + const [dialogFiltersToApply, setDialogFiltersToApply] = useState(currentLocationFiltersToApply); + const [filtersToApply, setFiltersToApply] = useState(currentLocationFiltersToApply); const searchTerm = useDebounce(query, 1000); const [resetScrollPosition, setResetScrollPosition] = useState(false); const [contentType, setContentType] = useState(currentLocationContentType); @@ -250,6 +254,15 @@ export default function SourceMangas() { [setContentType], ); + const updateLocationFilters = useCallback( + (updatedFilters: IPos[]) => { + if (contentType === SourceContentType.FILTER) { + navigate('', { replace: true, state: { contentType, filtersToApply: updatedFilters } }); + } + }, + [contentType], + ); + const isSearchTermAvailable = searchTerm && query?.length; const setSearchContentType = isSearchTermAvailable && contentType !== SourceContentType.SEARCH; if (setSearchContentType) { @@ -272,7 +285,9 @@ export default function SourceMangas() { const resetFilters = useCallback(async () => { setDialogFiltersToApply([]); setFiltersToApply([]); - }, [sourceId]); + updateLocationFilters([]); + setResetScrollPosition(true); + }, [sourceId, contentType]); useEffect( () => () => { @@ -360,6 +375,7 @@ export default function SourceMangas() { updateFilterValue={setDialogFiltersToApply} setTriggerUpdate={() => { setFiltersToApply(dialogFiltersToApply); + updateLocationFilters(dialogFiltersToApply); }} resetFilterValue={resetFilters} update={dialogFiltersToApply} From 78049282a770f912d4f28515937a3b7d0cd62658 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 25 Sep 2023 23:32:26 +0200 Subject: [PATCH 30/47] Use gql for "sources" - preferences --- src/components/source/filters/GroupFilter.tsx | 7 +- .../EditTextPreference.tsx | 15 +++-- .../sourceConfiguration/ListPreference.tsx | 22 ++++-- .../MultiSelectListPreference.tsx | 28 +++++--- .../TwoStatePreference.tsx | 39 +++++++++-- src/lib/requests/RequestManager.ts | 36 +++++----- src/screens/SourceConfigure.tsx | 36 +++++----- src/typings.ts | 67 +++++++++---------- 8 files changed, 147 insertions(+), 103 deletions(-) diff --git a/src/components/source/filters/GroupFilter.tsx b/src/components/source/filters/GroupFilter.tsx index f1cf7589..dd07d2e4 100644 --- a/src/components/source/filters/GroupFilter.tsx +++ b/src/components/source/filters/GroupFilter.tsx @@ -10,14 +10,11 @@ import { ExpandLess, ExpandMore } from '@mui/icons-material'; import { Collapse, ListItemButton, ListItemText, Stack, Box } from '@mui/material'; import React from 'react'; // eslint-disable-next-line import/no-cycle -import { SourceFilters } from '@/typings'; +import { ExtractByKeyValue, SourceFilters } from '@/typings'; import { Options } from '@/components/source/SourceOptions'; -// type ExcludeByName = T extends { __typename?: K } ? never : T; -type PickByName = T extends { __typename?: K } ? T : never; - interface Props { - state: PickByName['filters']; + state: ExtractByKeyValue['filters']; name: string; position: number; updateFilterValue: Function; diff --git a/src/components/sourceConfiguration/EditTextPreference.tsx b/src/components/sourceConfiguration/EditTextPreference.tsx index 45a58e8d..9a364b35 100644 --- a/src/components/sourceConfiguration/EditTextPreference.tsx +++ b/src/components/sourceConfiguration/EditTextPreference.tsx @@ -22,22 +22,29 @@ import { EditTextPreferenceProps } from '@/typings'; export default function EditTextPreference(props: EditTextPreferenceProps) { const { t } = useTranslation(); - const { title, summary, dialogTitle, dialogMessage, currentValue, updateValue } = props; + const { + EditTextPreferenceTitle: title, + summary, + dialogTitle, + dialogMessage, + EditTextPreferenceCurrentValue: currentValue, + updateValue, + } = props; - const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue); + const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue ?? ''); const [dialogOpen, setDialogOpen] = useState(false); const handleDialogCancel = () => { setDialogOpen(false); // reset the dialog - setInternalCurrentValue(currentValue); + setInternalCurrentValue(currentValue ?? ''); }; const handleDialogSubmit = () => { setDialogOpen(false); - updateValue(internalCurrentValue); + updateValue('editTextState', internalCurrentValue); }; return ( diff --git a/src/components/sourceConfiguration/ListPreference.tsx b/src/components/sourceConfiguration/ListPreference.tsx index 6cee2401..0460be0c 100644 --- a/src/components/sourceConfiguration/ListPreference.tsx +++ b/src/components/sourceConfiguration/ListPreference.tsx @@ -85,12 +85,20 @@ function ListDialog(props: IListDialogProps) { } export default function ListPreference(props: ListPreferenceProps) { - const { title, summary, currentValue, updateValue, entryValues, entries } = props; - const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue); + const { + ListPreferenceTitle: title, + summary, + ListPreferenceCurrentValue: currentValue, + ListPreferenceDefault: defaultValue, + updateValue, + entryValues, + entries, + } = props; + const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue ?? defaultValue ?? ''); const [dialogOpen, setDialogOpen] = useState(false); useEffect(() => { - setInternalCurrentValue(currentValue); + setInternalCurrentValue(currentValue ?? defaultValue ?? ''); }, [currentValue]); const findEntryOf = (value: string) => { @@ -104,6 +112,10 @@ export default function ListPreference(props: ListPreferenceProps) { }; const getSummary = () => { + if (currentValue == null) { + return ''; + } + if (summary === '%s') { return findEntryOf(currentValue); } @@ -112,7 +124,7 @@ export default function ListPreference(props: ListPreferenceProps) { const handleDialogClose = (newValue: string | null) => { if (newValue !== null) { - updateValue(findEntryValueOf(newValue)); + updateValue('listState', findEntryValueOf(newValue)); // appear smooth setInternalCurrentValue(newValue); @@ -127,7 +139,7 @@ export default function ListPreference(props: ListPreferenceProps) { (currentValue); + const { + MultiSelectListPreferenceTitle: title, + summary, + MultiSelectListPreferenceCurrentValue: currentValue, + MultiSelectListPreferenceDefault: defaultValue, + updateValue, + entryValues, + entries, + } = props; + const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue ?? defaultValue); const [dialogOpen, setDialogOpen] = useState(false); useEffect(() => { setInternalCurrentValue(currentValue); }, [currentValue]); - const findEntriesOf = (values: string[]) => - values.map((value) => { + const findEntriesOf = (values?: string[] | null) => + values?.map((value) => { const idx = entryValues.indexOf(value); return entries[idx]; - }); + }) ?? []; - const findEntryValuesOf = (values: string[]) => - values.map((value) => { + const findEntryValuesOf = (values?: string[] | null) => + values?.map((value) => { const idx = entries.indexOf(value); return entryValues[idx]; - }); + }) ?? []; const getSummary = () => summary; const handleDialogClose = (newValue: string[] | null) => { if (newValue !== null) { // console.log(newValue); - updateValue(findEntryValuesOf(newValue)); + updateValue('multiSelectState', findEntryValuesOf(newValue)); // appear smooth setInternalCurrentValue(newValue); @@ -139,7 +147,7 @@ export default function MultiSelectListPreference(props: MultiSelectListPreferen { + if (props.type === 'CheckBoxPreference') { + return { + title: props.CheckBoxTitle, + defaultValue: props.CheckBoxDefault, + currentValue: props.CheckBoxCheckBoxCurrentValue, + }; + } + + return { + title: props.SwitchPreferenceTitle, + defaultValue: props.SwitchPreferenceDefault, + currentValue: props.SwitchPreferenceCurrentValue, + }; +}; + function TwoSatePreference(props: TwoStatePreferenceProps) { - const { title, summary, currentValue, updateValue, type } = props; - const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue); + const { title, defaultValue, currentValue, summary, updateValue, twoStateType } = { + ...props, + ...getTwoStateValues(props), + }; + const [internalCurrentValue, setInternalCurrentValue] = useState(currentValue ?? defaultValue); useEffect(() => { - setInternalCurrentValue(currentValue); + setInternalCurrentValue(currentValue ?? defaultValue); }, [currentValue]); return ( - {createElement(getTwoStateType(type), { + {createElement(getTwoStateType(twoStateType), { edge: 'end', checked: internalCurrentValue, onChange: () => { - updateValue(!currentValue); + updateValue(twoStateType === 'Switch' ? 'switchState' : 'checkBoxState', !currentValue); // appear smooth setInternalCurrentValue(!currentValue); @@ -49,11 +74,11 @@ function TwoSatePreference(props: TwoStatePreferenceProps) { } export function CheckBoxPreference(props: CheckBoxPreferenceProps) { - return ; + return ; } export function SwitchPreferenceCompat(props: SwitchPreferenceCompatProps) { - return ; + return ; } export default { CheckBoxPreference, SwitchPreferenceCompat }; diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 7721e253..2a7e3fe3 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -24,13 +24,7 @@ import { } from '@apollo/client'; import { OperationVariables } from '@apollo/client/core'; import { useEffect, useRef, useState } from 'react'; -import { - BackupValidationResult, - IChapter, - IMangaChapter, - PaginatedList, - SourcePreferences, -} from '@/typings.ts'; +import { BackupValidationResult, IChapter, IMangaChapter, PaginatedList } from '@/typings.ts'; import { HttpMethod as DefaultHttpMethod, IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import storage from '@/util/localStorage.tsx'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; @@ -95,6 +89,7 @@ import { SetGlobalMetadataMutation, SetGlobalMetadataMutationVariables, SetMangaMetadataMutation, + SourcePreferenceChangeInput, StartDownloaderMutation, StartDownloaderMutationVariables, StopDownloaderMutation, @@ -123,6 +118,8 @@ import { UpdateMangaMutation, UpdateMangaMutationVariables, UpdateMangaPatchInput, + UpdateSourcePreferencesMutation, + UpdateSourcePreferencesMutationVariables, } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATA, GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; @@ -142,7 +139,7 @@ import { } from '@/lib/graphql/mutations/MangaMutation.ts'; import { GET_MANGA, GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts'; import { GET_CATEGORIES, GET_CATEGORY, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; -import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts'; +import { GET_SOURCE_MANGAS_FETCH, UPDATE_SOURCE_PREFERENCES } from '@/lib/graphql/mutations/SourceMutation.ts'; import { CLEAR_DOWNLOADER, DELETE_DOWNLOADED_CHAPTER, @@ -1195,15 +1192,20 @@ export class RequestManager { ); } - public useGetSourcePreferences( - sourceId: string, - swrOptions?: SWROptions, - ): AbortableSWRResponse { - return this.doRequest(HttpMethod.SWR_GET, `source/${sourceId}/preferences`, { swrOptions }); - } - - public setSourcePreferences(sourceId: string, position: number, value: string): AbortableAxiosResponse { - return this.doRequest(HttpMethod.POST, `source/${sourceId}/preferences`, { data: { position, value } }); + public setSourcePreferences( + source: string, + change: SourcePreferenceChangeInput, + options?: MutationOptions, + ): AbortableApolloMutationResponse { + return this.doRequestNew( + GQLMethod.MUTATION, + UPDATE_SOURCE_PREFERENCES, + { input: { source, change } }, + { + refetchQueries: [GET_SOURCE], + ...options, + }, + ); } public useSourceSearch( diff --git a/src/screens/SourceConfigure.tsx b/src/screens/SourceConfigure.tsx index 9fc74c3d..243106bd 100644 --- a/src/screens/SourceConfigure.tsx +++ b/src/screens/SourceConfigure.tsx @@ -17,12 +17,13 @@ import { SwitchPreferenceCompat, CheckBoxPreference } from '@/components/sourceC import ListPreference from '@/components/sourceConfiguration/ListPreference'; import EditTextPreference from '@/components/sourceConfiguration/EditTextPreference'; import MultiSelectListPreference from '@/components/sourceConfiguration/MultiSelectListPreference'; +import { PreferenceProps } from '@/typings.ts'; function getPrefComponent(type: string) { switch (type) { case 'CheckBoxPreference': return CheckBoxPreference; - case 'SwitchPreferenceCompat': + case 'SwitchPreference': return SwitchPreferenceCompat; case 'ListPreference': return ListPreference; @@ -31,7 +32,7 @@ function getPrefComponent(type: string) { case 'MultiSelectListPreference': return MultiSelectListPreference; default: - return CheckBoxPreference; + throw new Error(`Unexpected preference type "${type}"`); } } @@ -45,33 +46,26 @@ export default function SourceConfigure() { }, [t]); const { sourceId } = useParams<{ sourceId: string }>(); - const { data: sourcePreferences = [], mutate } = requestManager.useGetSourcePreferences(sourceId); + const { data } = requestManager.useGetSource(sourceId); + const sourcePreferences = data?.source.preferences ?? []; - const convertToString = (position: number, value: any): string => { - switch (sourcePreferences[position].props.defaultValueType) { - case 'Set': - return JSON.stringify(value); - default: - return value.toString(); - } - }; - - const updateValue = (position: number) => (value: any) => { - requestManager - .setSourcePreferences(sourceId, position, convertToString(position, value)) - .response.then(() => mutate()); - }; + const updateValue = + (position: number): PreferenceProps['updateValue'] => + (type, value) => { + requestManager.setSourcePreferences(sourceId, { position, [type]: value }); + }; return ( {sourcePreferences.map((it, index) => { - const props = cloneObject(it.props); - props.updateValue = updateValue(index); - props.key = index; + const props = cloneObject(it); // TypeScript is dumb in detecting extra props // @ts-ignore - return createElement(getPrefComponent(it.type), props); + return createElement(getPrefComponent(it.type), { + ...props, + updateValue: updateValue(index), + }); })} ); diff --git a/src/typings.ts b/src/typings.ts index ca0669cc..ea9255d6 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -10,7 +10,19 @@ import { OverridableComponent } from '@mui/material/OverridableComponent'; import { SvgIconTypeMap } from '@mui/material/SvgIcon/SvgIcon'; import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; -import { ExtensionType, GetSourceQuery, MangaType, MetaType } from '@/lib/graphql/generated/graphql.ts'; +import { + ExtensionType, + GetSourceQuery, + MangaType, + MetaType, + SourcePreferenceChangeInput, +} from '@/lib/graphql/generated/graphql.ts'; + +export type ExtractByKeyValue = T extends + | Record + | Partial> + ? T + : never; export type RecursivePartial = { [P in keyof T]?: T[P] extends (infer U)[] @@ -253,47 +265,34 @@ export interface IUpdateStatus { }; } +export type SourcePreferences = GetSourceQuery['source']['preferences'][number]; + export interface PreferenceProps { - key: string; - title: string; - summary: string; - defaultValue: any; - currentValue: any; - defaultValueType: string; + updateValue: >( + type: Key, + value: SourcePreferenceChangeInput[Key], + ) => void; +} +export type TwoStatePreferenceProps = (CheckBoxPreferenceProps | SwitchPreferenceCompatProps) & { // intetnal props - updateValue: any; -} + twoStateType: 'Switch' | 'Checkbox'; +}; -export interface TwoStatePreferenceProps extends PreferenceProps { - // intetnal props - type: 'Switch' | 'Checkbox'; -} +export type CheckBoxPreferenceProps = PreferenceProps & + ExtractByKeyValue; -export interface CheckBoxPreferenceProps extends PreferenceProps {} +export type SwitchPreferenceCompatProps = PreferenceProps & + ExtractByKeyValue; -export interface SwitchPreferenceCompatProps extends PreferenceProps {} +export type ListPreferenceProps = PreferenceProps & + ExtractByKeyValue; -export interface ListPreferenceProps extends PreferenceProps { - entries: string[]; - entryValues: string[]; -} +export type MultiSelectListPreferenceProps = PreferenceProps & + ExtractByKeyValue; -export interface MultiSelectListPreferenceProps extends PreferenceProps { - entries: string[]; - entryValues: string[]; -} - -export interface EditTextPreferenceProps extends PreferenceProps { - dialogTitle: string; - dialogMessage: string; - text: string; -} - -export interface SourcePreferences { - type: string; - props: any; -} +export type EditTextPreferenceProps = PreferenceProps & + ExtractByKeyValue; export interface NavbarItem { path: string; From aad87463f34d8fcbf547d67be5e2d9968156f559 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 30 Sep 2023 16:55:35 +0200 Subject: [PATCH 31/47] [Codegen] Use gql for "loading chapters" --- src/components/manga/ChapterCard.tsx | 61 +++--- src/components/manga/ChapterList.tsx | 104 +++++----- src/components/manga/ResumeFAB.tsx | 14 +- src/components/manga/SelectionFAB.tsx | 12 +- src/components/manga/hooks.ts | 13 +- src/components/manga/util.tsx | 17 +- src/components/navbar/ReaderNavBar.tsx | 20 +- src/lib/graphql/generated/apollo-helpers.ts | 3 +- src/lib/graphql/generated/graphql.ts | 2 +- src/lib/requests/RequestManager.ts | 209 +++++++++++++++++--- src/lib/requests/client/GraphQLClient.ts | 30 ++- src/screens/Manga.tsx | 2 +- src/screens/Reader.tsx | 98 +++++---- src/screens/Updates.tsx | 52 ++--- src/typings.ts | 10 +- tools/scripts/codegenFormatter.ts | 83 +++++++- 16 files changed, 500 insertions(+), 230 deletions(-) diff --git a/src/components/manga/ChapterCard.tsx b/src/components/manga/ChapterCard.tsx index 1b6962cb..13621bbf 100644 --- a/src/components/manga/ChapterCard.tsx +++ b/src/components/manga/ChapterCard.tsx @@ -27,16 +27,15 @@ import Typography from '@mui/material/Typography'; import React from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { IChapter, IDownloadChapter } from '@/typings'; +import { IDownloadChapter } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import { getUploadDateString } from '@/util/date'; import DownloadStateIndicator from '@/components/molecules/DownloadStateIndicator'; -import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; +import { ChapterType, UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; interface IProps { - chapter: IChapter; + chapter: ChapterType; chapterIds: number[]; - triggerChaptersUpdate: () => void; downloadChapter: IDownloadChapter | undefined; showChapterNumber: boolean; onSelect: (selected: boolean) => void; @@ -47,15 +46,7 @@ const ChapterCard: React.FC = (props: IProps) => { const { t } = useTranslation(); const theme = useTheme(); - const { - chapter, - chapterIds, - triggerChaptersUpdate, - downloadChapter: dc, - showChapterNumber, - onSelect, - selected, - } = props; + const { chapter, chapterIds, downloadChapter: dc, showChapterNumber, onSelect, selected } = props; const isSelecting = selected !== null; const [anchorEl, setAnchorEl] = React.useState(null); @@ -82,12 +73,10 @@ const ChapterCard: React.FC = (props: IProps) => { return; } - requestManager - .updateChapter(chapter.id, { - [key]: value, - lastPageRead: key === 'isRead' ? 0 : undefined, - }) - .response.then(() => triggerChaptersUpdate()); + requestManager.updateChapter(chapter.id, { + [key]: value, + lastPageRead: key === 'isRead' ? 0 : undefined, + }); }; const downloadChapter = () => { @@ -96,7 +85,7 @@ const ChapterCard: React.FC = (props: IProps) => { }; const deleteChapter = () => { - requestManager.deleteDownloadedChapter(chapter.id).response.then(() => triggerChaptersUpdate()); + requestManager.deleteDownloadedChapter(chapter.id); handleClose(); }; @@ -113,8 +102,8 @@ const ChapterCard: React.FC = (props: IProps) => { } }; - const isDownloaded = chapter.downloaded; - const canBeDownloaded = !chapter.downloaded && dc === undefined; + const { isDownloaded } = chapter; + const canBeDownloaded = !chapter.isDownloaded && dc === undefined; return (
  • @@ -126,9 +115,9 @@ const ChapterCard: React.FC = (props: IProps) => { > @@ -143,7 +132,7 @@ const ChapterCard: React.FC = (props: IProps) => { > - {chapter.bookmarked && ( + {chapter.isBookmarked && ( = (props: IProps) => { {chapter.scanlator} - {getUploadDateString(chapter.uploadDate)} + {getUploadDateString(Number(chapter.uploadDate ?? 0))} {isDownloaded && ` • ${t('chapter.status.label.downloaded')}`} @@ -192,24 +181,24 @@ const ChapterCard: React.FC = (props: IProps) => { {t('chapter.action.download.add.label.action')} )} - sendChange('isBookmarked', !chapter.bookmarked)}> + sendChange('isBookmarked', !chapter.isBookmarked)}> - {chapter.bookmarked && } - {!chapter.bookmarked && } + {chapter.isBookmarked && } + {!chapter.isBookmarked && } - {chapter.bookmarked && t('chapter.action.bookmark.remove.label.action')} - {!chapter.bookmarked && t('chapter.action.bookmark.add.label.action')} + {chapter.isBookmarked && t('chapter.action.bookmark.remove.label.action')} + {!chapter.isBookmarked && t('chapter.action.bookmark.add.label.action')} - sendChange('isRead', !chapter.read)}> + sendChange('isRead', !chapter.isRead)}> - {chapter.read && } - {!chapter.read && } + {chapter.isRead && } + {!chapter.isRead && } - {chapter.read && t('chapter.action.mark_as_read.remove.label.action')} - {!chapter.read && t('chapter.action.mark_as_read.add.label.action.current')} + {chapter.isRead && t('chapter.action.mark_as_read.remove.label.action')} + {!chapter.isRead && t('chapter.action.mark_as_read.add.label.action.current')} sendChange('markPrevRead', true)}> diff --git a/src/components/manga/ChapterList.tsx b/src/components/manga/ChapterList.tsx index 21b5b8e4..71e0d134 100644 --- a/src/components/manga/ChapterList.tsx +++ b/src/components/manga/ChapterList.tsx @@ -11,7 +11,7 @@ import Typography from '@mui/material/Typography'; import React, { ComponentProps, useEffect, useMemo, useRef, useState } from 'react'; import { Virtuoso } from 'react-virtuoso'; import { useTranslation } from 'react-i18next'; -import { IChapter, IDownloadChapter, IQueue, TranslationKey } from '@/typings'; +import { IDownloadChapter, IQueue, TranslationKey } from '@/typings'; import requestManager from '@/lib/requests/RequestManager.ts'; import useSubscription from '@/components/library/useSubscription'; import ChapterCard from '@/components/manga/ChapterCard'; @@ -22,7 +22,7 @@ import makeToast from '@/components/util/Toast'; import ChaptersToolbarMenu from '@/components/manga/ChaptersToolbarMenu'; import SelectionFAB from '@/components/manga/SelectionFAB'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab'; -import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; +import { ChapterType, MangaType, UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; const StyledVirtuoso = styled(Virtuoso)(({ theme }) => ({ listStyle: 'none', @@ -69,25 +69,29 @@ const actionsStrings: { }; export interface IChapterWithMeta { - chapter: IChapter; + chapter: ChapterType; downloadChapter: IDownloadChapter | undefined; selected: boolean | null; } interface IProps { - mangaId: string; + manga: MangaType; + isRefreshing: boolean; } -const ChapterList: React.FC = ({ mangaId }) => { +const ChapterList: React.FC = ({ manga, isRefreshing }) => { const { t } = useTranslation(); const [selection, setSelection] = useState(null); const prevQueueRef = useRef(); const queue = useSubscription('downloads').data?.queue; - const [options, dispatch] = useChapterOptions(mangaId); - const { data: chaptersData, mutate, isLoading } = requestManager.useGetMangaChapters(mangaId); - const chapters = useMemo(() => chaptersData ?? [], [chaptersData]); + const [options, dispatch] = useChapterOptions(manga.id); + const { data: chaptersData, loading: isLoading, refetch } = requestManager.useGetMangaChapters(manga.id); + const chapters = useMemo( + () => (chaptersData?.chapters.nodes as ChapterType[]) ?? [], + [chaptersData?.chapters.nodes], + ); const mangaChapterIds = useMemo(() => chapters.map((chapter) => chapter.id), [chapters]); useEffect(() => { @@ -102,26 +106,17 @@ const ChapterList: React.FC = ({ mangaId }) => { }); if (changedDownloads.length > 0) { - mutate(); + refetch(); } } prevQueueRef.current = queue; }, [queue]); - const visibleChapters = useMemo( - () => filterAndSortChapters(chapters, options), // - [chapters, options], - ); + const visibleChapters = useMemo(() => filterAndSortChapters(chapters, options), [chapters, options]); - const firstUnreadChapter = useMemo( - () => - chapters - .slice() - .reverse() - .find((chapter) => !chapter.read), - [chapters], - ); + const nextChapterIndexToRead = (manga.lastReadChapter?.sourceOrder ?? 0) + 1; + const isLatestChapterRead = manga.chapters.totalCount === manga.lastReadChapter?.sourceOrder; const handleSelection = (index: number) => { const chapter = visibleChapters[index]; @@ -174,11 +169,49 @@ const ChapterList: React.FC = ({ mangaId }) => { actionPromise .then(() => makeToast(t(actionsStrings[action].success, { count: chapterIds.length }), 'success')) - .then(() => mutate()) .catch(() => makeToast(t(actionsStrings[action].error, { count: chapterIds.length }), 'error')); }; - if (isLoading) { + const noChaptersFound = chapters.length === 0; + const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0; + + const chaptersWithMeta: IChapterWithMeta[] = useMemo( + () => + visibleChapters.map((chapter) => { + const downloadChapter = queue?.find( + (cd) => cd.chapterIndex === chapter.sourceOrder && cd.mangaId === chapter.manga.id, + ); + const selected = selection?.includes(chapter.id) ?? null; + return { + chapter, + downloadChapter, + selected, + }; + }), + [queue, selection, visibleChapters], + ); + + const selectedChapters = useMemo(() => { + if (!selection) { + return null; + } + + return chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id)); + }, [selection, chapters]); + + const chapterListFAB = useMemo(() => { + if (selectedChapters) { + return ; + } + + if (!isLatestChapterRead) { + return ; + } + + return null; + }, [selectedChapters, isLatestChapterRead]); + + if (isLoading || (noChaptersFound && isRefreshing)) { return (
    = ({ mangaId }) => { ); } - const noChaptersFound = chapters.length === 0; - const noChaptersMatchingFilter = !noChaptersFound && visibleChapters.length === 0; - - const chaptersWithMeta: IChapterWithMeta[] = visibleChapters.map((chapter) => { - const downloadChapter = queue?.find( - (cd) => cd.chapterIndex === chapter.index && cd.mangaId === chapter.mangaId, - ); - const selected = selection?.includes(chapter.id) ?? null; - return { - chapter, - downloadChapter, - selected, - }; - }); - - const selectedChapters = - selection === null ? null : chaptersWithMeta.filter(({ chapter }) => selection.includes(chapter.id)); - return ( <> @@ -273,7 +288,6 @@ const ChapterList: React.FC = ({ mangaId }) => { {...chaptersWithMeta[index]} chapterIds={mangaChapterIds} showChapterNumber={options.showChapterNumber} - triggerChaptersUpdate={() => mutate()} onSelect={() => handleSelection(index)} /> ); @@ -282,11 +296,7 @@ const ChapterList: React.FC = ({ mangaId }) => { overscan={window.innerHeight * 0.5} /> - {selectedChapters !== null ? ( - - ) : ( - firstUnreadChapter && - )} + {chapterListFAB} ); }; diff --git a/src/components/manga/ResumeFAB.tsx b/src/components/manga/ResumeFAB.tsx index 5c43c5d5..6e6c7eba 100644 --- a/src/components/manga/ResumeFAB.tsx +++ b/src/components/manga/ResumeFAB.tsx @@ -9,25 +9,21 @@ import { Link } from 'react-router-dom'; import { PlayArrow } from '@mui/icons-material'; import { useTranslation } from 'react-i18next'; -import { IChapter } from '@/typings'; import StyledFab from '@/components/util/StyledFab'; interface ResumeFABProps { - chapter: IChapter; - mangaId: string; + chapterIndex: number; + mangaId: number; } export default function ResumeFab(props: ResumeFABProps) { const { t } = useTranslation(); - const { - chapter: { index }, - mangaId, - } = props; + const { chapterIndex, mangaId } = props; return ( - + - {index === 1 ? t('global.button.start') : t('global.button.resume')} + {chapterIndex === 1 ? t('global.button.start') : t('global.button.resume')} ); } diff --git a/src/components/manga/SelectionFAB.tsx b/src/components/manga/SelectionFAB.tsx index bd2c0de4..93d1e514 100644 --- a/src/components/manga/SelectionFAB.tsx +++ b/src/components/manga/SelectionFAB.tsx @@ -63,38 +63,38 @@ const SelectionFAB: React.FC = (props) => { !c.downloaded && dc === undefined, + ({ chapter: c, downloadChapter: dc }) => !c.isDownloaded && dc === undefined, )} onClick={handleAction} title={t('chapter.action.download.add.button.selected')} /> chapter.downloaded)} + matchingChapters={selectedChapters.filter(({ chapter }) => chapter.isDownloaded)} onClick={handleAction} title={t('chapter.action.download.delete.button.selected')} /> !chapter.bookmarked)} + matchingChapters={selectedChapters.filter(({ chapter }) => !chapter.isBookmarked)} onClick={handleAction} title={t('chapter.action.bookmark.add.button.selected')} /> chapter.bookmarked)} + matchingChapters={selectedChapters.filter(({ chapter }) => chapter.isBookmarked)} onClick={handleAction} title={t('chapter.action.bookmark.remove.button.selected')} /> !chapter.read)} + matchingChapters={selectedChapters.filter(({ chapter }) => !chapter.isRead)} onClick={handleAction} title={t('chapter.action.mark_as_read.add.button.selected')} /> chapter.read)} + matchingChapters={selectedChapters.filter(({ chapter }) => chapter.isRead)} onClick={handleAction} title={t('chapter.action.mark_as_read.remove.button.selected')} /> diff --git a/src/components/manga/hooks.ts b/src/components/manga/hooks.ts index 4327641a..7eb1e41f 100644 --- a/src/components/manga/hooks.ts +++ b/src/components/manga/hooks.ts @@ -7,8 +7,7 @@ */ import { useCallback, useEffect, useState } from 'react'; -import { mutate } from 'swr'; -import requestManager, { RequestManager } from '@/lib/requests/RequestManager.ts'; +import requestManager from '@/lib/requests/RequestManager.ts'; export const useRefreshManga = (mangaId: string) => { const [fetchingOnline, setFetchingOnline] = useState(false); @@ -16,14 +15,8 @@ export const useRefreshManga = (mangaId: string) => { const handleRefresh = useCallback(async () => { setFetchingOnline(true); await Promise.all([ - requestManager.getMangaFetch(mangaId).response.then((res) => { - mutate(`${RequestManager.API_VERSION}manga/${mangaId}`, res, { revalidate: false }); - }), - requestManager.getMangaChapters(mangaId, true).response.then((res) => - mutate(`${RequestManager.API_VERSION}manga/${mangaId}/chapters`, res, { - revalidate: false, - }), - ), + requestManager.getMangaFetch(mangaId, { awaitRefetchQueries: true }).response, + requestManager.getMangaChaptersFetch(mangaId, { awaitRefetchQueries: true }).response, ]).finally(() => setFetchingOnline(false)); }, [mangaId]); diff --git a/src/components/manga/util.tsx b/src/components/manga/util.tsx index 27073b1a..edfb25c0 100644 --- a/src/components/manga/util.tsx +++ b/src/components/manga/util.tsx @@ -11,11 +11,11 @@ import { ChapterListOptions, ChapterOptionsReducerAction, ChapterSortMode, - IChapter, NullAndUndefined, TranslationKey, } from '@/typings'; import { useReducerLocalStorage } from '@/util/useLocalStorage'; +import { ChapterType } from '@/lib/graphql/generated/graphql.ts'; const defaultChapterOptions: ChapterListOptions = { active: false, @@ -46,7 +46,7 @@ function chapterOptionsReducer(state: ChapterListOptions, actions: ChapterOption } } -export function unreadFilter(unread: NullAndUndefined, { read: isChapterRead }: IChapter) { +export function unreadFilter(unread: NullAndUndefined, { isRead: isChapterRead }: ChapterType) { switch (unread) { case true: return !isChapterRead; @@ -57,7 +57,7 @@ export function unreadFilter(unread: NullAndUndefined, { read: isChapte } } -function downloadFilter(downloaded: NullAndUndefined, { downloaded: chapterDownload }: IChapter) { +function downloadFilter(downloaded: NullAndUndefined, { isDownloaded: chapterDownload }: ChapterType) { switch (downloaded) { case true: return chapterDownload; @@ -68,7 +68,7 @@ function downloadFilter(downloaded: NullAndUndefined, { downloaded: cha } } -function bookmarkedFilter(bookmarked: NullAndUndefined, { bookmarked: chapterBookmarked }: IChapter) { +function bookmarkedFilter(bookmarked: NullAndUndefined, { isBookmarked: chapterBookmarked }: ChapterType) { switch (bookmarked) { case true: return chapterBookmarked; @@ -79,7 +79,7 @@ function bookmarkedFilter(bookmarked: NullAndUndefined, { bookmarked: c } } -export function filterAndSortChapters(chapters: IChapter[], options: ChapterListOptions): IChapter[] { +export function filterAndSortChapters(chapters: ChapterType[], options: ChapterListOptions): ChapterType[] { const filtered = options.active ? chapters.filter( (chp) => @@ -88,14 +88,17 @@ export function filterAndSortChapters(chapters: IChapter[], options: ChapterList bookmarkedFilter(options.bookmarked, chp), ) : [...chapters]; - const Sorted = options.sortBy === 'fetchedAt' ? filtered.sort((a, b) => a.fetchedAt - b.fetchedAt) : filtered; + const Sorted = + options.sortBy === 'fetchedAt' + ? filtered.sort((a, b) => Number(a.fetchedAt ?? 0) - Number(b.fetchedAt ?? 0)) + : filtered; if (options.reverse) { Sorted.reverse(); } return Sorted; } -export const useChapterOptions = (mangaId: string) => +export const useChapterOptions = (mangaId: number) => useReducerLocalStorage( chapterOptionsReducer, `${mangaId}filterOptions`, diff --git a/src/components/navbar/ReaderNavBar.tsx b/src/components/navbar/ReaderNavBar.tsx index b95ef730..236e6474 100644 --- a/src/components/navbar/ReaderNavBar.tsx +++ b/src/components/navbar/ReaderNavBar.tsx @@ -24,9 +24,9 @@ import ListItemText from '@mui/material/ListItemText'; import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; import Collapse from '@mui/material/Collapse'; import { useTranslation } from 'react-i18next'; -import { ChapterOffset, IChapter, IReaderSettings } from '@/typings'; +import { ChapterOffset, IReaderSettings } from '@/typings'; import ReaderSettingsOptions from '@/components/reader/ReaderSettingsOptions'; -import { MangaType } from '@/lib/graphql/generated/graphql.ts'; +import { ChapterType, MangaType } from '@/lib/graphql/generated/graphql.ts'; const Root = styled('div')(({ theme }) => ({ top: 0, @@ -115,8 +115,8 @@ const OpenDrawerButton = styled(IconButton)(({ theme }) => ({ interface IProps { settings: IReaderSettings; setSettingValue: (key: keyof IReaderSettings, value: string | boolean) => void; - manga: Pick; - chapter: IChapter; + manga: MangaType; + chapter: ChapterType; curPage: number; scrollToPage: (page: number) => void; openNextChapter: (offset: ChapterOffset, setHistory: (nextChapterIndex: number) => void) => Promise; @@ -304,7 +304,7 @@ export default function ReaderNavBar(props: IProps) { openNextChapter(ChapterOffset.PREV, (prevChapterIndex) => { navigate(`/manga/${manga.id}/chapter/${prevChapterIndex}`, { @@ -322,11 +322,11 @@ export default function ReaderNavBar(props: IProps) {