2023-05-18 13:25:19 +02:00
/*
* 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/.
*/
2023-06-04 00:30:48 +02:00
import { AxiosInstance , AxiosRequestConfig } from 'axios' ;
2023-06-08 13:40:50 +02:00
import useSWR , { Middleware , SWRConfiguration , SWRResponse } from 'swr' ;
2023-05-18 13:25:19 +02:00
import useSWRInfinite , { SWRInfiniteConfiguration , SWRInfiniteResponse } from 'swr/infinite' ;
2023-09-01 20:21:59 +02:00
import {
FetchResult ,
MutationHookOptions ,
MutationOptions ,
MutationTuple ,
QueryHookOptions ,
QueryResult ,
TypedDocumentNode ,
useMutation ,
useQuery ,
} from '@apollo/client' ;
import { OperationVariables } from '@apollo/client/core' ;
2023-09-08 00:06:24 +02:00
import { useState } from 'react' ;
2023-05-18 13:25:19 +02:00
import {
BackupValidationResult ,
ICategory ,
IChapter ,
IMangaChapter ,
ISourceFilters ,
PaginatedList ,
2023-05-20 13:12:23 +02:00
PaginatedMangaList ,
2023-05-18 13:25:19 +02:00
SourcePreferences ,
SourceSearchResult ,
2023-08-15 13:54:29 +02:00
} from '@/typings.ts' ;
2023-08-15 13:54:55 +02:00
import { HttpMethod as DefaultHttpMethod , IRestClient , RestClient } from '@/lib/requests/client/RestClient.ts' ;
2023-08-15 13:54:29 +02:00
import storage from '@/util/localStorage.tsx' ;
2023-09-01 20:21:59 +02:00
import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts' ;
2023-09-01 20:24:40 +02:00
import {
2023-09-01 20:39:30 +02:00
CategoryOrderBy ,
2023-09-01 20:26:06 +02:00
CheckForServerUpdatesQuery ,
CheckForServerUpdatesQueryVariables ,
2023-09-01 20:40:24 +02:00
ClearDownloaderMutation ,
ClearDownloaderMutationVariables ,
2023-09-01 20:39:30 +02:00
CreateCategoryInput ,
CreateCategoryMutation ,
CreateCategoryMutationVariables ,
DeleteCategoryMutation ,
DeleteCategoryMutationVariables ,
2023-09-01 20:36:40 +02:00
DeleteDownloadedChapterMutation ,
DeleteDownloadedChapterMutationVariables ,
DeleteDownloadedChaptersMutation ,
DeleteDownloadedChaptersMutationVariables ,
2023-09-01 20:40:24 +02:00
DequeueChapterDownloadMutation ,
DequeueChapterDownloadMutationVariables ,
DequeueChapterDownloadsMutation ,
DequeueChapterDownloadsMutationVariables ,
EnqueueChapterDownloadMutation ,
EnqueueChapterDownloadMutationVariables ,
EnqueueChapterDownloadsMutation ,
EnqueueChapterDownloadsMutationVariables ,
2023-09-08 00:06:24 +02:00
FetchSourceMangaInput ,
FetchSourceMangaType ,
FilterChangeInput ,
2023-09-01 20:25:46 +02:00
GetAboutQuery ,
GetAboutQueryVariables ,
2023-09-01 20:28:23 +02:00
GetExtensionsFetchMutation ,
GetExtensionsFetchMutationVariables ,
2023-09-01 20:39:30 +02:00
GetCategoriesQuery ,
GetCategoriesQueryVariables ,
2023-09-06 21:47:13 +02:00
GetCategoryMangasQuery ,
GetCategoryMangasQueryVariables ,
2023-09-01 20:28:23 +02:00
GetExtensionsQuery ,
GetExtensionsQueryVariables ,
2023-09-01 20:24:40 +02:00
GetGlobalMetadatasQuery ,
GetGlobalMetadatasQueryVariables ,
2023-09-08 00:44:01 +02:00
GetMangaFetchMutation ,
GetMangaFetchMutationVariables ,
GetMangaQuery ,
GetMangaQueryVariables ,
2023-09-08 00:06:24 +02:00
GetSourceMangasFetchMutation ,
GetSourceMangasFetchMutationVariables ,
2023-09-01 20:29:19 +02:00
GetSourceQuery ,
GetSourceQueryVariables ,
GetSourcesQuery ,
GetSourcesQueryVariables ,
2023-09-01 20:40:39 +02:00
GetUpdateStatusQuery ,
GetUpdateStatusQueryVariables ,
2023-09-01 20:28:23 +02:00
InstallExternalExtensionMutation ,
InstallExternalExtensionMutationVariables ,
2023-09-01 20:40:24 +02:00
ReorderChapterDownloadMutation ,
ReorderChapterDownloadMutationVariables ,
2023-09-01 20:39:30 +02:00
SetCategoryMetadataMutation ,
SetCategoryMetadataMutationVariables ,
2023-09-01 20:36:40 +02:00
SetChapterMetadataMutation ,
SetChapterMetadataMutationVariables ,
2023-09-01 20:24:40 +02:00
SetGlobalMetadataMutation ,
SetGlobalMetadataMutationVariables ,
2023-09-01 20:33:35 +02:00
SetMangaMetadataMutation ,
2023-09-01 20:40:24 +02:00
StartDownloaderMutation ,
StartDownloaderMutationVariables ,
StopDownloaderMutation ,
StopDownloaderMutationVariables ,
2023-09-01 20:40:39 +02:00
StopUpdaterMutation ,
StopUpdaterMutationVariables ,
UpdateCategoryMangasMutation ,
UpdateCategoryMangasMutationVariables ,
2023-09-01 20:39:30 +02:00
UpdateCategoryMutation ,
UpdateCategoryMutationVariables ,
UpdateCategoryOrderMutation ,
UpdateCategoryOrderMutationVariables ,
UpdateCategoryPatchInput ,
2023-09-01 20:36:40 +02:00
UpdateChapterMutation ,
UpdateChapterMutationVariables ,
UpdateChapterPatchInput ,
UpdateChaptersMutation ,
UpdateChaptersMutationVariables ,
2023-09-01 20:28:23 +02:00
UpdateExtensionMutation ,
UpdateExtensionMutationVariables ,
UpdateExtensionPatchInput ,
2023-09-01 20:40:39 +02:00
UpdateLibraryMangasMutation ,
UpdateLibraryMangasMutationVariables ,
2023-09-01 20:33:35 +02:00
UpdateMangaCategoriesMutation ,
UpdateMangaCategoriesMutationVariables ,
UpdateMangaMutation ,
UpdateMangaMutationVariables ,
UpdateMangaPatchInput ,
2023-09-01 20:24:40 +02:00
} 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' ;
2023-09-01 20:26:06 +02:00
import { CHECK_FOR_SERVER_UPDATES , GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts' ;
2023-09-01 20:28:23 +02:00
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' ;
2023-09-01 20:29:19 +02:00
import { GET_SOURCE , GET_SOURCES } from '@/lib/graphql/queries/SourceQuery.ts' ;
2023-09-08 00:44:01 +02:00
import {
GET_MANGA_FETCH ,
SET_MANGA_METADATA ,
UPDATE_MANGA ,
UPDATE_MANGA_CATEGORIES ,
} from '@/lib/graphql/mutations/MangaMutation.ts' ;
2023-09-01 20:33:35 +02:00
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' ;
2023-09-01 20:40:24 +02:00
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' ;
2023-09-01 20:36:40 +02:00
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' ;
2023-09-01 20:39:30 +02:00
import {
CREATE_CATEGORY ,
DELETE_CATEGORY ,
SET_CATEGORY_METADATA ,
UPDATE_CATEGORY ,
UPDATE_CATEGORY_ORDER ,
} from '@/lib/graphql/mutations/CategoryMutation.ts' ;
2023-09-01 20:40:24 +02:00
import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts' ;
2023-09-01 20:40:39 +02:00
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' ;
2023-05-18 13:25:19 +02:00
enum SWRHttpMethod {
SWR_GET ,
SWR_GET_INFINITE ,
SWR_POST ,
2023-05-22 14:04:05 +02:00
SWR_POST_INFINITE ,
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:21:59 +02:00
enum GQLMethod {
USE_QUERY = 'USE_QUERY' ,
USE_MUTATION = 'USE_MUTATION' ,
MUTATION = 'MUTATION' ,
}
2023-05-18 13:25:19 +02:00
type HttpMethodType = DefaultHttpMethod | SWRHttpMethod ;
const HttpMethod = { ... SWRHttpMethod , ... DefaultHttpMethod };
type RequestOption = { doOnlineFetch? : boolean };
type CustomSWROptions < Data > = {
skipRequest? : boolean ;
getEndpoint ?: ( index : number , previousData : Data | null ) => string | null ;
2023-06-08 13:40:50 +02:00
disableCache? : boolean ;
2023-05-18 13:25:19 +02:00
};
type SWROptions < Data = any , Error = any > = SWRConfiguration < Data , Error > & CustomSWROptions < Data >;
type SWRInfiniteOptions < Data = any , Error = any > = SWRInfiniteConfiguration < Data , Error > & CustomSWROptions < Data >;
2023-05-28 02:18:23 +02:00
type SWRInfiniteResponseLoadInfo = {
isInitialLoad : boolean ;
isLoadMore : boolean ;
};
2023-05-23 13:27:38 +02:00
type AbortableRequest = { abortRequest : AbortController [ 'abort' ] };
2023-06-04 00:30:48 +02:00
export type AbortableAxiosResponse < Data = any > = { response : Promise < Data > } & AbortableRequest ;
2023-05-28 12:16:06 +02:00
export type AbortableSWRResponse < Data = any , Error = any > = SWRResponse < Data , Error > & AbortableRequest ;
export type AbortableSWRInfiniteResponse < Data = any , Error = any > = SWRInfiniteResponse < Data , Error > &
2023-05-28 02:18:23 +02:00
AbortableRequest &
SWRInfiniteResponseLoadInfo ;
2023-05-23 13:27:38 +02:00
2023-09-01 20:21:59 +02:00
type AbortableApolloUseQueryResponse <
Data = any ,
Variables extends OperationVariables = OperationVariables ,
> = QueryResult < Data , Variables > & AbortableRequest ;
type AbortableApolloUseMutationResponse < Data = any , Variables extends OperationVariables = OperationVariables > = [
MutationTuple < Data , Variables >[ 0 ],
MutationTuple < Data , Variables >[ 1 ] & AbortableRequest ,
];
2023-09-08 00:06:24 +02:00
type AbortableApolloUseMutationPaginatedResponse <
Data = any ,
Variables extends OperationVariables = OperationVariables ,
> = [
( page : number ) => Promise < FetchResult < Data >>,
( MutationTuple < Data , Variables >[ 1 ] & AbortableRequest & { size : number ; loadingMore : boolean })[],
];
2023-09-01 20:21:59 +02:00
type AbortableApolloMutationResponse < Data = any > = { response : Promise < FetchResult < Data >> } & AbortableRequest ;
2023-06-08 13:40:50 +02:00
const isLoadingMore = ( swrResult : SWRInfiniteResponse ) : boolean => {
const isNextPageMissing = !! swrResult . data && typeof swrResult . data [ swrResult . size - 1 ] === 'undefined' ;
2023-06-16 00:14:22 +02:00
const isRequestActive = swrResult . isValidating ;
2023-06-08 13:40:50 +02:00
// SWR "isLoading" state is only updated for the first load, for every subsequent load it's "false"
2023-06-16 00:14:22 +02:00
return ! swrResult . isLoading && swrResult . size > 0 && isNextPageMissing && isRequestActive ;
2023-06-08 13:40:50 +02:00
};
const disableSwrInfiniteCache : Middleware = ( useSWRNext ) => ( key , fetcher , config ) => {
const swr = useSWRNext ( key , fetcher , config ) as unknown as SWRInfiniteResponse ;
const { size , data , isLoading , isValidating } = swr ;
const isActuallyValidating = ! isLoading && ! isLoadingMore ( swr ) && isValidating ;
return {
... swr ,
isLoading : isActuallyValidating ? true : isLoading ,
data : isActuallyValidating ? undefined : data ,
size : isActuallyValidating ? 1 : size ,
} as SWRResponse ;
};
const disableSwrCache : Middleware = ( useSWRNext ) => ( key , fetcher , config ) => {
const swr = useSWRNext ( key , fetcher , config );
const { data , isLoading , isValidating } = swr ;
return { ... swr , isLoading : isValidating ? true : isLoading , data : isValidating ? undefined : data };
};
2023-05-18 13:25:19 +02:00
// the following endpoints have not been implemented:
// - PUT /api/v1/manga/{mangaId}/chapter/{chapterIndex} - modify chapter # PATCH endpoint used instead
// - POST /api/v1/backup/import - import backup # "import backup file" endpoint used instead
// - POST /api/v1/backup/validate - validate backup # "validate backup file" endpoint used instead
// - GET /api/v1/backup/export - export backup # no function needed, url gets called via link triggering the download
export class RequestManager {
2023-06-04 00:50:58 +02:00
public static readonly API_VERSION = '/api/v1/' ;
2023-05-18 13:25:19 +02:00
2023-09-01 20:21:59 +02:00
private readonly graphQLClient = new GraphQLClient ();
2023-05-18 13:25:19 +02:00
private readonly restClient : RestClient = new RestClient ();
public getClient () : IRestClient {
return this . restClient ;
}
2023-05-23 13:25:48 +02:00
public updateClient ( config : Partial < AxiosInstance [ 'defaults' ] >) : void {
2023-05-18 13:25:19 +02:00
this . restClient . updateConfig ( config );
2023-09-01 20:21:59 +02:00
this . graphQLClient . updateConfig ({ uri : config.baseURL });
2023-05-18 13:25:19 +02:00
}
public getBaseUrl () : string {
return this . restClient . getClient (). defaults . baseURL ! ;
}
public getWebSocketBaseUrl () : string {
return this . getBaseUrl (). replace ( 'http' , 'ws' );
}
public getValidWebSocketUrl ( path : string , apiVersion = RequestManager . API_VERSION ) : string {
return ` ${ this . getWebSocketBaseUrl () }${ apiVersion }${ path } ` ;
}
public getUpdateWebSocket () : WebSocket {
return new WebSocket ( this . getValidWebSocketUrl ( 'update' ));
}
public getDownloadWebSocket () : WebSocket {
return new WebSocket ( this . getValidWebSocketUrl ( 'downloads' ));
}
public getValidUrlFor ( endpoint : string , apiVersion : string = RequestManager . API_VERSION ) : string {
return ` ${ this . getBaseUrl () }${ apiVersion }${ endpoint } ` ;
}
public getValidImgUrlFor ( imageUrl : string , apiVersion : string = '' ) : string {
const useCache = storage . getItem ( 'useCache' , true );
const useCacheQuery = `?useCache= ${ useCache } ` ;
// server provided image urls already contain the api version
return ` ${ this . getValidUrlFor ( imageUrl , apiVersion ) }${ useCacheQuery } ` ;
}
2023-09-01 20:21:59 +02:00
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables >(
method : GQLMethod.USE_QUERY ,
operation : TypedDocumentNode < Data , Variables >,
variables : Variables ,
options? : Partial < QueryHookOptions < Data , Variables >>,
) : AbortableApolloUseQueryResponse < Data , Variables >;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables >(
method : GQLMethod.USE_MUTATION ,
operation : TypedDocumentNode < Data , Variables >,
variables : Variables | undefined ,
options? : Partial < MutationHookOptions < Data , Variables >>,
) : AbortableApolloUseMutationResponse < Data , Variables >;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables >(
method : GQLMethod.MUTATION ,
operation : TypedDocumentNode < Data , Variables >,
variables : Variables ,
options? : Partial < MutationOptions < Data , Variables >>,
) : AbortableApolloMutationResponse < Data >;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables >(
method : GQLMethod ,
operation : TypedDocumentNode < Data , Variables >,
variables : Variables ,
options ?:
| QueryHookOptions < Data , Variables >
| MutationHookOptions < Data , Variables >
| MutationOptions < Data , Variables >,
) :
| AbortableApolloUseQueryResponse < Data , Variables >
| AbortableApolloUseMutationResponse < Data , Variables >
| AbortableApolloMutationResponse < Data > {
const abortController = new AbortController ();
const abortRequest = ( reason? : any ) : void => {
if ( ! abortController . signal . aborted ) {
abortController . abort ( reason );
}
};
switch ( method ) {
case GQLMethod.USE_QUERY :
return {
... useQuery < Data , Variables >( 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 < Data , Variables >( operation , {
variables ,
client : this.graphQLClient.client ,
...( options as MutationHookOptions < Data , Variables >),
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 < Data , Variables >({
mutation : operation ,
variables ,
...( options as MutationOptions < Data , Variables >),
context : {
... options ? . context ,
fetchOptions : {
signal : abortController.signal ,
... options ? . context ? . fetchOptions ,
},
},
}),
abortRequest ,
};
default :
throw new Error ( `unexpected GQLRequest type " ${ method } "` );
}
}
2023-05-18 13:25:19 +02:00
private useSwr <
Data = any ,
ErrorResponse = any ,
OptionsSWR extends SWROptions < Data , ErrorResponse > = SWROptions < Data , ErrorResponse >,
> (
url : string ,
httpMethod : DefaultHttpMethod ,
{
data ,
axiosOptions ,
swrOptions ,
} : {
data? : Data ;
axiosOptions? : AxiosRequestConfig ;
swrOptions? : OptionsSWR ;
} = {},
) : SWRResponse < Data , ErrorResponse > {
2023-06-08 13:40:50 +02:00
const { skipRequest , disableCache , ... swrConfig } = swrOptions ?? {};
2023-05-18 13:25:19 +02:00
// in case "null" gets passed as the url, SWR won't do the request
return useSWR ( skipRequest ? null : url , {
fetcher : ( path : string ) => this . restClient . fetcher ( path , { data , httpMethod , config : axiosOptions }),
2023-06-08 13:40:50 +02:00
use : disableCache ? [ disableSwrCache ] : undefined ,
2023-05-18 13:25:19 +02:00
... swrConfig ,
});
}
2023-05-20 13:12:23 +02:00
public useSwrInfinite <
Data = any ,
ErrorResponse = any ,
OptionsSWR extends SWRInfiniteOptions < Data , ErrorResponse > = SWRInfiniteOptions < Data , ErrorResponse >,
> (
2023-05-18 13:25:19 +02:00
getEndpoint : Required < CustomSWROptions < Data >>[ 'getEndpoint' ],
2023-05-22 14:04:05 +02:00
httpMethod : DefaultHttpMethod ,
{
data ,
axiosOptions ,
swrOptions ,
} : { data? : any ; axiosOptions? : AxiosRequestConfig ; swrOptions? : OptionsSWR } = {},
2023-05-28 02:18:23 +02:00
) : SWRInfiniteResponse < Data , ErrorResponse > & SWRInfiniteResponseLoadInfo {
2023-06-08 13:40:50 +02:00
const { skipRequest , disableCache , ... swrConfig } = swrOptions ?? {};
2023-05-20 13:12:23 +02:00
2023-05-18 13:25:19 +02:00
// useSWRInfinite will (by default) revalidate the first page, to check if the other pages have to be revalidated as well
2023-05-28 02:18:23 +02:00
const swrResult = useSWRInfinite < Data , ErrorResponse >(
2023-05-18 13:25:19 +02:00
( index , previousData ) => {
const pageEndpoint = getEndpoint ( index , previousData );
2023-05-20 13:12:23 +02:00
return pageEndpoint !== null && ! skipRequest ? this . getValidUrlFor ( pageEndpoint ) : null ;
2023-05-18 13:25:19 +02:00
},
{
2023-05-22 14:04:05 +02:00
fetcher : ( path : string ) => this . restClient . fetcher ( path , { httpMethod , data , config : axiosOptions }),
2023-06-08 13:40:50 +02:00
use : disableCache ? [ disableSwrInfiniteCache ] : undefined ,
2023-05-20 13:12:23 +02:00
... swrConfig ,
2023-05-18 13:25:19 +02:00
},
);
2023-05-28 02:18:23 +02:00
const customSwrResult = {
... swrResult ,
isInitialLoad : swrResult.isLoading ,
2023-06-08 13:40:50 +02:00
isLoadMore : isLoadingMore ( swrResult ),
2023-05-18 13:25:19 +02:00
};
2023-05-28 02:18:23 +02:00
customSwrResult . isLoading = customSwrResult . isInitialLoad || customSwrResult . isLoadMore ;
return customSwrResult ;
2023-05-18 13:25:19 +02:00
}
/**
* Performs the actual server request.
*
* In case {@link HttpMethod.GET_SWR} gets passed, the "useSWR" hook gets called.
* In case {@link HttpMethod.GET_SWR_INFINITE} gets passed, the "useSWRInfinite" hook gets called.
* In that case "getEndpoint" has to be passed, which gets used over "endpoint"
*
* Pass "skipRequest" to make SWR skip sending the request to the server.
* In case "formData" is passed, "data" gets ignored.
*/
private doRequest <
2023-05-23 13:27:38 +02:00
Result extends AbortableAxiosResponse | AbortableSWRResponse | AbortableSWRInfiniteResponse ,
2023-05-18 13:25:19 +02:00
OptionsSWR extends SWROptions | SWRInfiniteOptions ,
> (
httpMethod : HttpMethodType ,
endpoint : string ,
{
apiVersion = RequestManager . API_VERSION ,
data : dataToSend ,
formData ,
axiosOptions ,
swrOptions ,
} : {
apiVersion? : string ;
data? : any ;
formData ?: { [ key : string ] : any };
axiosOptions? : AxiosRequestConfig ;
swrOptions? : OptionsSWR ;
} = {},
) : Result {
const url = ` ${ apiVersion }${ endpoint } ` ;
let data = dataToSend ;
if ( formData ) {
data = new FormData ();
Object . entries ( formData ). forEach (([ key , value ]) => {
2023-06-04 00:32:08 +02:00
if ( value !== undefined ) data . append ( key , value ); // "append" automatically converts non string or blob values to strings
2023-05-18 13:25:19 +02:00
});
}
2023-05-23 13:27:38 +02:00
const abortController = new AbortController ();
const abortRequest = ( reason? : any ) : void => {
if ( ! abortController . signal . aborted ) {
abortController . abort ( reason );
}
};
const axiosOptionsWithAbortController = { ... axiosOptions , signal : abortController.signal };
2023-05-18 13:25:19 +02:00
switch ( httpMethod ) {
case HttpMethod.SWR_GET :
2023-05-23 13:27:38 +02:00
return {
...( this . useSwr ( url , HttpMethod . GET , { axiosOptions , swrOptions }) as Result ),
abortRequest ,
};
2023-05-18 13:25:19 +02:00
case HttpMethod . SWR_GET_INFINITE :
// throw TypeError in case options aren't correctly passed
2023-05-23 13:27:38 +02:00
return {
...( this . useSwrInfinite ( swrOptions ! . getEndpoint ! , HttpMethod . GET , {
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
}) as Result ),
abortRequest ,
};
2023-05-22 14:04:05 +02:00
case SWRHttpMethod.SWR_POST_INFINITE :
2023-05-23 13:27:38 +02:00
return {
...( this . useSwrInfinite ( swrOptions ! . getEndpoint ! , HttpMethod . POST , {
data ,
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
}) as Result ),
abortRequest ,
};
2023-05-18 13:25:19 +02:00
case HttpMethod.SWR_POST :
2023-05-23 13:27:38 +02:00
return {
...( this . useSwr ( url , HttpMethod . POST , {
data ,
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
}) as Result ),
controller : abortController ,
};
2023-05-18 13:25:19 +02:00
default :
2023-05-23 13:27:38 +02:00
return {
response : this.restClient.fetcher ( url , {
data ,
httpMethod ,
config : axiosOptionsWithAbortController ,
checkResponseIsJson : false ,
}),
abortRequest ,
} as Result ;
2023-05-18 13:25:19 +02:00
}
}
2023-09-01 20:24:40 +02:00
public useGetGlobalMeta (
options? : QueryHookOptions < GetGlobalMetadatasQuery , GetGlobalMetadatasQueryVariables >,
) : AbortableApolloUseQueryResponse < GetGlobalMetadatasQuery , GetGlobalMetadatasQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_GLOBAL_METADATAS , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:24:40 +02:00
public setGlobalMetadata ( key : string , value : any ) : AbortableApolloMutationResponse < SetGlobalMetadataMutation > {
return this . doRequestNew < SetGlobalMetadataMutation , SetGlobalMetadataMutationVariables >(
GQLMethod . MUTATION ,
SET_GLOBAL_METADATA ,
{ input : { meta : { key , value : ` ${ value } ` } } },
{ refetchQueries : [ GET_GLOBAL_METADATA , GET_GLOBAL_METADATAS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:25:46 +02:00
public useGetAbout (
options? : QueryHookOptions < GetAboutQuery , GetAboutQueryVariables >,
) : AbortableApolloUseQueryResponse < GetAboutQuery , GetAboutQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_ABOUT , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:26:06 +02:00
public useCheckForUpdate (
options? : QueryHookOptions < CheckForServerUpdatesQuery , CheckForServerUpdatesQueryVariables >,
) : AbortableApolloUseQueryResponse < CheckForServerUpdatesQuery , CheckForServerUpdatesQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , CHECK_FOR_SERVER_UPDATES , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public useGetExtensionList (
options? : QueryHookOptions < GetExtensionsQuery , GetExtensionsQueryVariables >,
) : AbortableApolloUseQueryResponse < GetExtensionsQuery , GetExtensionsQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_EXTENSIONS , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public useExtensionListFetch (
options? : MutationHookOptions < GetExtensionsFetchMutation , GetExtensionsFetchMutationVariables >,
) : AbortableApolloUseMutationResponse < GetExtensionsFetchMutation , GetExtensionsFetchMutationVariables > {
return this . doRequestNew ( GQLMethod . USE_MUTATION , GET_EXTENSIONS_FETCH , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public installExternalExtension (
extensionFile : File ,
) : AbortableApolloMutationResponse < InstallExternalExtensionMutation > {
return this . doRequestNew < InstallExternalExtensionMutation , InstallExternalExtensionMutationVariables >(
GQLMethod . MUTATION ,
INSTALL_EXTERNAL_EXTENSION ,
{ file : extensionFile },
{ refetchQueries : [ GET_EXTENSION , GET_EXTENSIONS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public updateExtension (
id : string ,
patch : UpdateExtensionPatchInput ,
) : AbortableApolloMutationResponse < UpdateExtensionMutation > {
return this . doRequestNew < UpdateExtensionMutation , UpdateExtensionMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_EXTENSION ,
{ input : { id , patch } },
{ refetchQueries : [ GET_EXTENSION , GET_EXTENSIONS , GET_SOURCES ] },
);
2023-05-18 13:25:19 +02:00
}
public getExtensionIconUrl ( extension : string ) : string {
return this . getValidImgUrlFor ( `extension/icon/ ${ extension } ` );
}
2023-09-01 20:29:19 +02:00
public useGetSourceList (
options? : QueryHookOptions < GetSourcesQuery , GetSourcesQueryVariables >,
) : AbortableApolloUseQueryResponse < GetSourcesQuery , GetSourcesQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_SOURCES , {}, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:29:19 +02:00
public useGetSource (
id : string ,
options? : QueryHookOptions < GetSourceQuery , GetSourceQueryVariables >,
) : AbortableApolloUseQueryResponse < GetSourceQuery , GetSourceQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_SOURCE , { id }, options );
2023-05-18 13:25:19 +02:00
}
2023-09-08 00:06:24 +02:00
public useGetSourceMangas (
input : FetchSourceMangaInput ,
options? : MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables >,
) : 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 < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables >(
GQLMethod . USE_MUTATION ,
GET_SOURCE_MANGAS_FETCH ,
{ input },
options ,
);
const [ previousResults , setPreviousResults ] = useState < AbortableApolloUseMutationPaginatedResponse [ 1 ] >([
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 ];
}
2023-05-18 13:25:19 +02:00
public useGetSourcePopularMangas (
sourceId : string ,
initialPages? : number ,
2023-05-20 13:12:23 +02:00
swrOptions? : SWRInfiniteOptions < PaginatedMangaList >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedMangaList > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( SWRHttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) =>
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ?? true ? `source/ ${ sourceId } /popular/ ${ page + 1 } ` : null ,
2023-05-18 13:25:19 +02:00
initialSize : initialPages ,
... swrOptions ,
} as typeof swrOptions ,
});
}
public useGetSourceLatestMangas (
sourceId : string ,
initialPages? : number ,
2023-05-20 13:12:23 +02:00
swrOptions? : SWRInfiniteOptions < PaginatedMangaList >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedMangaList > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( SWRHttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) =>
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ?? true ? `source/ ${ sourceId } /latest/ ${ page + 1 } ` : null ,
2023-05-18 13:25:19 +02:00
initialSize : initialPages ,
... swrOptions ,
} as typeof swrOptions ,
});
}
public useGetSourcePreferences (
sourceId : string ,
swrOptions? : SWROptions < SourcePreferences [] >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < SourcePreferences [] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , `source/ ${ sourceId } /preferences` , { swrOptions });
}
2023-05-23 13:27:38 +02:00
public setSourcePreferences ( sourceId : string , position : number , value : string ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . POST , `source/ ${ sourceId } /preferences` , { data : { position , value } });
}
public useGetSourceFilters (
sourceId : string ,
reset? : boolean ,
swrOptions? : SWROptions < ISourceFilters [] >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < ISourceFilters [] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , `source/ ${ sourceId } /filters` , { swrOptions });
}
2023-05-23 13:27:38 +02:00
public setSourceFilters ( sourceId : string , filters : { position : number ; state : string }[]) : AbortableAxiosResponse {
2023-05-22 14:03:50 +02:00
return this . doRequest ( HttpMethod . POST , `source/ ${ sourceId } /filters` , { data : filters });
2023-05-18 13:25:19 +02:00
}
2023-05-23 13:27:38 +02:00
public resetSourceFilters ( sourceId : string ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . GET , `source/ ${ sourceId } /filters?reset=true` );
}
public useSourceSearch (
2023-09-08 00:06:24 +02:00
source : string ,
query : string ,
filters? : FilterChangeInput [],
options? : MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables >,
) : AbortableApolloUseMutationPaginatedResponse <
GetSourceMangasFetchMutation ,
GetSourceMangasFetchMutationVariables
> {
return this . useGetSourceMangas ({ type : FetchSourceMangaType . Search , source , query , filters , page : 1 }, options );
2023-05-18 13:25:19 +02:00
}
public useSourceQuickSearch (
sourceId : string ,
searchTerm : string ,
filters : { position : number ; state : string }[],
initialPages? : number ,
swrOptions? : SWRInfiniteOptions < SourceSearchResult >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < SourceSearchResult > {
2023-05-22 14:04:05 +02:00
return this . doRequest ( HttpMethod . SWR_POST_INFINITE , '' , {
data : { searchTerm , filter : filters },
2023-05-18 13:25:19 +02:00
swrOptions : {
getEndpoint : ( page , previousData ) =>
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ?? true
? `source/ ${ sourceId } /quick-search?searchTerm= ${ searchTerm } &pageNum= ${ page + 1 } `
2023-05-18 13:25:19 +02:00
: null ,
initialSize : initialPages ,
... swrOptions ,
} as typeof swrOptions ,
});
}
public useGetManga (
mangaId : number | string ,
2023-09-08 00:44:01 +02:00
options? : QueryHookOptions < GetMangaQuery , GetMangaQueryVariables >,
) : AbortableApolloUseQueryResponse < GetMangaQuery , GetMangaQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_MANGA , { id : Number ( mangaId ) }, options );
2023-05-18 13:25:19 +02:00
}
2023-09-08 00:44:01 +02:00
public getMangaFetch (
2023-05-18 13:25:19 +02:00
mangaId : number | string ,
2023-09-08 00:44:01 +02:00
options? : MutationOptions < GetMangaFetchMutation , GetMangaFetchMutationVariables >,
) : AbortableApolloMutationResponse < GetMangaFetchMutation > {
return this . doRequestNew < GetMangaFetchMutation , GetMangaFetchMutationVariables >(
GQLMethod . MUTATION ,
GET_MANGA_FETCH ,
{
input : {
id : Number ( mangaId ),
},
},
{
refetchQueries : [ GET_MANGA , GET_MANGAS ],
... options ,
},
);
2023-05-18 13:25:19 +02:00
}
public getMangaThumbnailUrl ( mangaId : number ) : string {
return this . getValidImgUrlFor ( `manga/ ${ mangaId } /thumbnail` );
}
2023-05-23 13:27:38 +02:00
public useGetMangaCategories (
mangaId : number ,
swrOptions? : SWROptions < ICategory [] >,
) : AbortableSWRResponse < ICategory [] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , `manga/ ${ mangaId } /category` , { swrOptions });
}
2023-09-01 20:33:35 +02:00
public useUpdateMangaCategories (
options? : MutationHookOptions < UpdateMangaCategoriesMutation , UpdateMangaCategoriesMutationVariables >,
) : AbortableApolloUseMutationResponse < UpdateMangaCategoriesMutation , UpdateMangaCategoriesMutationVariables > {
return this . doRequestNew ( GQLMethod . USE_MUTATION , UPDATE_MANGA_CATEGORIES , undefined , {
refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY , GET_CATEGORIES , GET_CATEGORY_MANGAS ],
... options ,
});
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:33:35 +02:00
public updateManga (
id : number ,
patch : UpdateMangaPatchInput ,
options? : MutationHookOptions < UpdateMangaMutation , UpdateMangaMutationVariables >,
) : AbortableApolloMutationResponse < UpdateMangaMutation > {
return this . doRequestNew < UpdateMangaMutation , UpdateMangaMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_MANGA ,
{ input : { id , patch } },
{
refetchQueries : [
GET_MANGA ,
GET_MANGAS ,
GET_CATEGORY_MANGAS ,
GET_CATEGORY ,
GET_CATEGORIES ,
GET_SOURCE_MANGAS_FETCH ,
],
... options ,
},
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:33:35 +02:00
public setMangaMeta (
mangaId : number ,
key : string ,
value : any ,
) : AbortableApolloMutationResponse < SetMangaMetadataMutation > {
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 ] },
);
2023-05-18 13:25:19 +02:00
}
public useGetMangaChapters (
mangaId : number | string ,
{ doOnlineFetch , ... swrOptions } : SWROptions < IChapter [] > & RequestOption = {},
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < IChapter [] > {
2023-05-18 13:25:19 +02:00
const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : '' ;
return this . doRequest ( HttpMethod . SWR_GET , `manga/ ${ mangaId } /chapters ${ onlineFetch } ` , {
swrOptions ,
});
}
2023-06-04 00:50:58 +02:00
public getMangaChapters ( mangaId : number | string , doOnlineFetch? : boolean ) : AbortableAxiosResponse < IChapter [] > {
const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : '' ;
return this . doRequest ( HttpMethod . GET , `manga/ ${ mangaId } /chapters ${ onlineFetch } ` );
}
2023-05-18 13:25:19 +02:00
public useGetChapter (
mangaId : number | string ,
chapterIndex : number | string ,
swrOptions? : SWROptions < IChapter >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < IChapter > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , `manga/ ${ mangaId } /chapter/ ${ chapterIndex } ` , {
swrOptions ,
});
}
2023-06-04 00:50:58 +02:00
public getChapter ( mangaId : number | string , chapterIndex : number | string ) : AbortableAxiosResponse < IChapter > {
return this . doRequest ( HttpMethod . GET , `manga/ ${ mangaId } /chapter/ ${ chapterIndex } ` );
}
2023-09-01 20:36:40 +02:00
public deleteDownloadedChapter ( id : number ) : AbortableApolloMutationResponse < DeleteDownloadedChapterMutation > {
return this . doRequestNew < DeleteDownloadedChapterMutation , DeleteDownloadedChapterMutationVariables >(
GQLMethod . MUTATION ,
DELETE_DOWNLOADED_CHAPTER ,
{ input : { id } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTERS ] },
);
}
public deleteDownloadedChapters ( ids : number []) : AbortableApolloMutationResponse < DeleteDownloadedChaptersMutation > {
return this . doRequestNew < DeleteDownloadedChaptersMutation , DeleteDownloadedChaptersMutationVariables >(
GQLMethod . MUTATION ,
DELETE_DOWNLOADED_CHAPTERS ,
{ input : { ids } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTERS ] },
);
2023-05-18 13:25:19 +02:00
}
public updateChapter (
2023-09-01 20:36:40 +02:00
id : number ,
patch : UpdateChapterPatchInput ,
) : AbortableApolloMutationResponse < UpdateChapterMutation > {
return this . doRequestNew < UpdateChapterMutation , UpdateChapterMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_CHAPTER ,
{ input : { id , patch } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTER , GET_CHAPTERS ] },
);
2023-05-18 13:25:19 +02:00
}
public setChapterMeta (
2023-09-01 20:36:40 +02:00
chapterId : number ,
2023-05-18 13:25:19 +02:00
key : string ,
value : any ,
2023-09-01 20:36:40 +02:00
) : AbortableApolloMutationResponse < SetChapterMetadataMutation > {
return this . doRequestNew < SetChapterMetadataMutation , SetChapterMetadataMutationVariables >(
GQLMethod . MUTATION ,
SET_CHAPTER_METADATA ,
{ input : { meta : { chapterId , key , value : ` ${ value } ` } } },
{ refetchQueries : [ GET_CHAPTER , GET_CHAPTERS ] },
);
2023-05-18 13:25:19 +02:00
}
public getChapterPageUrl ( mangaId : number | string , chapterIndex : number | string , page : number ) : string {
return this . getValidImgUrlFor (
`manga/ ${ mangaId } /chapter/ ${ chapterIndex } /page/ ${ page } ` ,
RequestManager . API_VERSION ,
);
}
2023-09-01 20:36:40 +02:00
public updateChapters (
ids : number [],
patch : UpdateChapterPatchInput ,
) : AbortableApolloMutationResponse < UpdateChaptersMutation > {
return this . doRequestNew < UpdateChaptersMutation , UpdateChaptersMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_CHAPTERS ,
{ input : { ids , patch } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTER , GET_CHAPTERS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public useGetCategories () : AbortableApolloUseQueryResponse < GetCategoriesQuery , GetCategoriesQueryVariables > {
return this . doRequestNew < GetCategoriesQuery , GetCategoriesQueryVariables >( GQLMethod . USE_QUERY , GET_CATEGORIES , {
orderBy : CategoryOrderBy.Order ,
2023-05-18 13:25:19 +02:00
});
}
2023-09-01 20:39:30 +02:00
public createCategory ( input : CreateCategoryInput ) : AbortableApolloMutationResponse < CreateCategoryMutation > {
return this . doRequestNew < CreateCategoryMutation , CreateCategoryMutationVariables >(
GQLMethod . MUTATION ,
CREATE_CATEGORY ,
{ input },
{ refetchQueries : [ GET_CATEGORIES ] },
);
}
public reorderCategory ( id : number , position : number ) : AbortableApolloMutationResponse < UpdateCategoryOrderMutation > {
return this . doRequestNew < UpdateCategoryOrderMutation , UpdateCategoryOrderMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_CATEGORY_ORDER ,
{ input : { id , position } },
{ refetchQueries : [ GET_CATEGORIES ] },
);
}
2023-09-06 21:47:13 +02:00
public useGetCategoryMangas (
id : number ,
options? : QueryHookOptions < GetCategoryMangasQuery , GetCategoryMangasQueryVariables >,
) : AbortableApolloUseQueryResponse < GetCategoryMangasQuery , GetCategoryMangasQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_CATEGORY_MANGAS , { id }, options );
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public deleteCategory ( categoryId : number ) : AbortableApolloMutationResponse < DeleteCategoryMutation > {
return this . doRequestNew < DeleteCategoryMutation , DeleteCategoryMutationVariables >(
GQLMethod . MUTATION ,
DELETE_CATEGORY ,
{ input : { categoryId } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORIES ] },
);
2023-05-18 13:25:19 +02:00
}
public updateCategory (
2023-09-01 20:39:30 +02:00
id : number ,
patch : UpdateCategoryPatchInput ,
) : AbortableApolloMutationResponse < UpdateCategoryMutation > {
return this . doRequestNew < UpdateCategoryMutation , UpdateCategoryMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_CATEGORY ,
{ input : { id , patch } },
{ refetchQueries : [ GET_CATEGORY , GET_CATEGORIES ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public setCategoryMeta (
categoryId : number ,
key : string ,
value : any ,
) : AbortableApolloMutationResponse < SetCategoryMetadataMutation > {
return this . doRequestNew < SetCategoryMetadataMutation , SetCategoryMetadataMutationVariables >(
GQLMethod . MUTATION ,
SET_CATEGORY_METADATA ,
{ input : { meta : { categoryId , key , value : ` ${ value } ` } } },
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY , GET_CATEGORIES ] },
);
2023-05-18 13:25:19 +02:00
}
2023-05-23 13:27:38 +02:00
public restoreBackupFile ( file : File ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . POST , 'backup/import/file' , { formData : { 'backup.proto.gz' : file } });
}
public useValidateBackupFile (
file : File ,
swrOptions? : SWROptions < BackupValidationResult >,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < BackupValidationResult > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_POST , 'backup/validate/file' , {
formData : { 'backup.proto.gz' : file },
swrOptions ,
});
}
public getExportBackupUrl () : string {
return this . getValidUrlFor ( 'backup/export/file' );
}
2023-09-01 20:40:24 +02:00
public startDownloads () : AbortableApolloMutationResponse < StartDownloaderMutation > {
return this . doRequestNew < StartDownloaderMutation , StartDownloaderMutationVariables >(
GQLMethod . MUTATION ,
START_DOWNLOADER ,
{},
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public stopDownloads () : AbortableApolloMutationResponse < StopDownloaderMutation > {
return this . doRequestNew < StopDownloaderMutation , StopDownloaderMutationVariables >(
GQLMethod . MUTATION ,
STOP_DOWNLOADER ,
{},
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public clearDownloads () : AbortableApolloMutationResponse < ClearDownloaderMutation > {
return this . doRequestNew < ClearDownloaderMutation , ClearDownloaderMutationVariables >(
GQLMethod . MUTATION ,
CLEAR_DOWNLOADER ,
{},
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public addChapterToDownloadQueue ( id : number ) : AbortableApolloMutationResponse < EnqueueChapterDownloadMutation > {
return this . doRequestNew < EnqueueChapterDownloadMutation , EnqueueChapterDownloadMutationVariables >(
GQLMethod . MUTATION ,
ENQUEUE_CHAPTER_DOWNLOAD ,
{ input : { id } },
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public removeChapterFromDownloadQueue ( id : number ) : AbortableApolloMutationResponse < DequeueChapterDownloadMutation > {
return this . doRequestNew < DequeueChapterDownloadMutation , DequeueChapterDownloadMutationVariables >(
GQLMethod . MUTATION ,
DEQUEUE_CHAPTER_DOWNLOAD ,
{ input : { id } },
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
public reorderChapterInDownloadQueue (
2023-09-01 20:40:24 +02:00
chapterId : number ,
2023-05-18 13:25:19 +02:00
position : number ,
2023-09-01 20:40:24 +02:00
) : AbortableApolloMutationResponse < ReorderChapterDownloadMutation > {
return this . doRequestNew < ReorderChapterDownloadMutation , ReorderChapterDownloadMutationVariables >(
GQLMethod . MUTATION ,
REORDER_CHAPTER_DOWNLOAD ,
{ input : { chapterId , to : position } },
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public addChaptersToDownloadQueue ( ids : number []) : AbortableApolloMutationResponse < EnqueueChapterDownloadsMutation > {
return this . doRequestNew < EnqueueChapterDownloadsMutation , EnqueueChapterDownloadsMutationVariables >(
GQLMethod . MUTATION ,
ENQUEUE_CHAPTER_DOWNLOADS ,
{ input : { ids } },
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public removeChaptersFromDownloadQueue (
ids : number [],
) : AbortableApolloMutationResponse < DequeueChapterDownloadsMutation > {
return this . doRequestNew < DequeueChapterDownloadsMutation , DequeueChapterDownloadsMutationVariables >(
GQLMethod . MUTATION ,
DEQUEUE_CHAPTER_DOWNLOADS ,
{ input : { ids } },
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] },
);
2023-05-18 13:25:19 +02:00
}
public useGetRecentlyUpdatedChapters (
initialPages? : number ,
swrOptions? : SWRInfiniteOptions < PaginatedList < IMangaChapter >>,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedList < IMangaChapter >> {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) =>
previousData ? . hasNextPage ?? true ? `update/recentChapters/ ${ page } ` : null ,
initialSize : initialPages ,
... swrOptions ,
} as typeof swrOptions ,
});
}
2023-09-01 20:40:39 +02:00
public startGlobalUpdate () : AbortableApolloMutationResponse < UpdateLibraryMangasMutation >;
public startGlobalUpdate ( categories : number []) : AbortableApolloMutationResponse < UpdateCategoryMangasMutation >;
public startGlobalUpdate (
categories? : number [],
) : AbortableApolloMutationResponse < UpdateCategoryMangasMutation | UpdateLibraryMangasMutation > {
if ( categories ? . length ) {
return this . doRequestNew < UpdateCategoryMangasMutation , UpdateCategoryMangasMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_CATEGORY_MANGAS ,
{ input : { categories } },
);
}
return this . doRequestNew < UpdateLibraryMangasMutation , UpdateLibraryMangasMutationVariables >(
GQLMethod . MUTATION ,
UPDATE_LIBRARY_MANGAS ,
{},
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:39 +02:00
public resetGlobalUpdate () : AbortableApolloMutationResponse < StopUpdaterMutation > {
return this . doRequestNew < StopUpdaterMutation , StopUpdaterMutationVariables >(
GQLMethod . MUTATION ,
STOP_UPDATER ,
{},
);
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:39 +02:00
public useGetGlobalUpdateSummary (
options? : QueryHookOptions < GetUpdateStatusQuery , GetUpdateStatusQueryVariables >,
) : AbortableApolloUseQueryResponse < GetUpdateStatusQuery , GetUpdateStatusQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_UPDATE_STATUS , {}, options );
2023-05-18 13:25:19 +02:00
}
}
const requestManager = new RequestManager ();
export default requestManager ;