Introduce "koration" duration api
This commit is contained in:
@@ -65,6 +65,7 @@
|
|||||||
"i18next-http-backend": "3.0.2",
|
"i18next-http-backend": "3.0.2",
|
||||||
"immer": "10.1.1",
|
"immer": "10.1.1",
|
||||||
"jsonrepair": "3.13.0",
|
"jsonrepair": "3.13.0",
|
||||||
|
"koration": "0.1.0",
|
||||||
"material-ui-popup-state": "5.3.6",
|
"material-ui-popup-state": "5.3.6",
|
||||||
"mui-nested-menu": "4.0.1",
|
"mui-nested-menu": "4.0.1",
|
||||||
"node-vibrant": "4.0.3",
|
"node-vibrant": "4.0.3",
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export function EmptyView({ message, messageExtra, retry, noFaces, sx }: EmptyVi
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
minWidth: '-webkit-fill-available',
|
minWidth: 'fill-available',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
minHeight: '100%',
|
minHeight: '100%',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function EmptyViewAbsoluteCentered({ sx, ...emptyViewProps }: EmptyViewPr
|
|||||||
{...emptyViewProps}
|
{...emptyViewProps}
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
minHeight: '-webkit-fill-available',
|
minHeight: 'fill-available',
|
||||||
...sx,
|
...sx,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { d } from 'koration';
|
||||||
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
import { useLocalStorage } from '@/base/hooks/useStorage.tsx';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
const UPDATE_CHECK_INTERVAL = 1000 * 60 * 60; // 1 hour
|
const UPDATE_CHECK_INTERVAL = d(1).hours.inWholeMilliseconds;
|
||||||
const UPDATE_REMINDER_THRESHOLD = 1000 * 60 * 60; // 1 hour
|
const UPDATE_REMINDER_THRESHOLD = d(1).hours.inWholeMilliseconds;
|
||||||
|
|
||||||
export const useUpdateChecker = (
|
export const useUpdateChecker = (
|
||||||
storageKey: string,
|
storageKey: string,
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ export const BACKUP_FLAG_GROUP_TO_TRANSLATION: Record<BackupFlagGroup, Translati
|
|||||||
export const BACKUP_FLAGS = Object.keys(BACKUP_FLAGS_TO_TRANSLATION) as readonly BackupFlag[];
|
export const BACKUP_FLAGS = Object.keys(BACKUP_FLAGS_TO_TRANSLATION) as readonly BackupFlag[];
|
||||||
|
|
||||||
export const BACKUP_FLAGS_BY_GROUP: Record<BackupFlagGroup, BackupFlag[]> = {
|
export const BACKUP_FLAGS_BY_GROUP: Record<BackupFlagGroup, BackupFlag[]> = {
|
||||||
[BackupFlagGroup.LIBRARY]: ['includeManga', 'includeChapters', 'includeTracking', 'includeHistory', 'includeCategories'],
|
[BackupFlagGroup.LIBRARY]: [
|
||||||
|
'includeManga',
|
||||||
|
'includeChapters',
|
||||||
|
'includeTracking',
|
||||||
|
'includeHistory',
|
||||||
|
'includeCategories',
|
||||||
|
],
|
||||||
[BackupFlagGroup.SETTINGS]: ['includeClientData', 'includeServerSettings'],
|
[BackupFlagGroup.SETTINGS]: ['includeClientData', 'includeServerSettings'],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ import PushPinIcon from '@mui/icons-material/PushPin';
|
|||||||
import DoneAllIcon from '@mui/icons-material/DoneAll';
|
import DoneAllIcon from '@mui/icons-material/DoneAll';
|
||||||
import FilterListIcon from '@mui/icons-material/FilterList';
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
||||||
import { useElementSize } from '@mantine/hooks';
|
import { useElementSize } from '@mantine/hooks';
|
||||||
import IconButton from '@mui/material/IconButton'; // ms
|
import IconButton from '@mui/material/IconButton';
|
||||||
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
||||||
|
import { d } from 'koration';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { AppbarSearch } from '@/base/components/AppbarSearch.tsx';
|
import { AppbarSearch } from '@/base/components/AppbarSearch.tsx';
|
||||||
import { useDebounce } from '@/base/hooks/useDebounce.ts';
|
import { useDebounce } from '@/base/hooks/useDebounce.ts';
|
||||||
@@ -110,7 +111,7 @@ const compareSourcesBySearchResult = (
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
const TRIGGER_SEARCH_THRESHOLD = 1000; // ms
|
const TRIGGER_SEARCH_THRESHOLD = d(1).seconds.inWholeMilliseconds;
|
||||||
|
|
||||||
const SourceSearchPreview = React.memo(
|
const SourceSearchPreview = React.memo(
|
||||||
({
|
({
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LongPressPointerHandlers, LongPressResult } from 'use-long-press/lib/use-long-press.types';
|
import { LongPressPointerHandlers, LongPressResult } from 'node_modules/use-long-press/lib/use-long-press.types';
|
||||||
import { PopupState } from 'material-ui-popup-state/hooks';
|
import { PopupState } from 'material-ui-popup-state/hooks';
|
||||||
import type { JSX } from 'react';
|
import type { JSX } from 'react';
|
||||||
import { SelectableCollectionReturnType } from '@/base/collection/hooks/useSelectableCollection.ts';
|
import { SelectableCollectionReturnType } from '@/base/collection/hooks/useSelectableCollection.ts';
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import Stack from '@mui/material/Stack';
|
|||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
import InputAdornment from '@mui/material/InputAdornment';
|
import InputAdornment from '@mui/material/InputAdornment';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
import { d } from 'koration';
|
||||||
import { IReaderSettings } from '@/features/reader/Reader.types.ts';
|
import { IReaderSettings } from '@/features/reader/Reader.types.ts';
|
||||||
import { AUTO_SCROLL_SPEED } from '@/features/reader/settings/ReaderSettings.constants.tsx';
|
import { AUTO_SCROLL_SPEED } from '@/features/reader/settings/ReaderSettings.constants.tsx';
|
||||||
import { coerceIn } from '@/lib/HelperFunctions.ts';
|
import { coerceIn } from '@/lib/HelperFunctions.ts';
|
||||||
@@ -62,7 +63,10 @@ export const ReaderNavBarDesktopAutoScroll = ({
|
|||||||
setAutoScroll({ ...autoScroll, value }, false);
|
setAutoScroll({ ...autoScroll, value }, false);
|
||||||
|
|
||||||
clearTimeout(updateTimeout.current);
|
clearTimeout(updateTimeout.current);
|
||||||
updateTimeout.current = setTimeout(() => setAutoScroll({ ...autoScroll, value }, true), 1000);
|
updateTimeout.current = setTimeout(
|
||||||
|
() => setAutoScroll({ ...autoScroll, value }, true),
|
||||||
|
d(1).seconds.inWholeMilliseconds,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -8,13 +8,14 @@
|
|||||||
|
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { d } from 'koration';
|
||||||
import { IReaderSettings, IReaderSettingsWithDefaultFlag } from '@/features/reader/Reader.types.ts';
|
import { IReaderSettings, IReaderSettingsWithDefaultFlag } from '@/features/reader/Reader.types.ts';
|
||||||
import { makeToast } from '@/base/utils/Toast.ts';
|
import { makeToast } from '@/base/utils/Toast.ts';
|
||||||
import { READING_MODE_VALUE_TO_DISPLAY_DATA } from '@/features/reader/settings/ReaderSettings.constants.tsx';
|
import { READING_MODE_VALUE_TO_DISPLAY_DATA } from '@/features/reader/settings/ReaderSettings.constants.tsx';
|
||||||
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
|
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
|
||||||
import { TranslationKey } from '@/base/Base.types.ts';
|
import { TranslationKey } from '@/base/Base.types.ts';
|
||||||
|
|
||||||
const HIDE_PREVIEW_TIMEOUT = 5000;
|
const HIDE_PREVIEW_TIMEOUT = d(5).seconds.inWholeMilliseconds;
|
||||||
|
|
||||||
export const useReaderShowSettingPreviewOnChange = (
|
export const useReaderShowSettingPreviewOnChange = (
|
||||||
isLoading: boolean,
|
isLoading: boolean,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import { MutableRefObject, RefObject, useCallback, useEffect } from 'react';
|
import { MutableRefObject, RefObject, useCallback, useEffect } from 'react';
|
||||||
import { Direction } from '@mui/material/styles';
|
import { Direction } from '@mui/material/styles';
|
||||||
import { t as translate } from 'i18next';
|
import { t as translate } from 'i18next';
|
||||||
|
import { d } from 'koration';
|
||||||
import {
|
import {
|
||||||
getNextIndexFromPage,
|
getNextIndexFromPage,
|
||||||
getNextPageIndex,
|
getNextPageIndex,
|
||||||
@@ -473,7 +474,10 @@ export class ReaderControls {
|
|||||||
|
|
||||||
clearTimeout(ReaderControls.updateCurrentPageTimeout);
|
clearTimeout(ReaderControls.updateCurrentPageTimeout);
|
||||||
if (debounceChapterUpdate) {
|
if (debounceChapterUpdate) {
|
||||||
ReaderControls.updateCurrentPageTimeout = setTimeout(handleCurrentPageIndexChange, 1000);
|
ReaderControls.updateCurrentPageTimeout = setTimeout(
|
||||||
|
handleCurrentPageIndexChange,
|
||||||
|
d(1).seconds.inWholeMilliseconds,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { MutableRefObject, useEffect, useRef } from 'react';
|
import { MutableRefObject, useEffect, useRef } from 'react';
|
||||||
|
import { d } from 'koration';
|
||||||
|
|
||||||
export const useReaderHideCursorOnInactivity = (scrollElementRef: MutableRefObject<HTMLDivElement | null>) => {
|
export const useReaderHideCursorOnInactivity = (scrollElementRef: MutableRefObject<HTMLDivElement | null>) => {
|
||||||
const mouseInactiveTimeout = useRef<NodeJS.Timeout>(undefined);
|
const mouseInactiveTimeout = useRef<NodeJS.Timeout>(undefined);
|
||||||
@@ -26,7 +27,7 @@ export const useReaderHideCursorOnInactivity = (scrollElementRef: MutableRefObje
|
|||||||
clearTimeout(mouseInactiveTimeout.current);
|
clearTimeout(mouseInactiveTimeout.current);
|
||||||
mouseInactiveTimeout.current = setTimeout(() => {
|
mouseInactiveTimeout.current = setTimeout(() => {
|
||||||
setCursorVisibility(false);
|
setCursorVisibility(false);
|
||||||
}, 5000);
|
}, d(5).seconds.inWholeMilliseconds);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseMove();
|
handleMouseMove();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import { d } from 'koration';
|
||||||
import { DEFAULT_DEVICE } from '@/features/device/services/Device.ts';
|
import { DEFAULT_DEVICE } from '@/features/device/services/Device.ts';
|
||||||
import { DEFAULT_SORT_SETTINGS } from '@/features/migration/Migration.constants.ts';
|
import { DEFAULT_SORT_SETTINGS } from '@/features/migration/Migration.constants.ts';
|
||||||
import { GlobalUpdateSkipEntriesSettings, MetadataServerSettings } from '@/features/settings/Settings.types.ts';
|
import { GlobalUpdateSkipEntriesSettings, MetadataServerSettings } from '@/features/settings/Settings.types.ts';
|
||||||
@@ -170,9 +170,9 @@ export const WEB_UI_INTERFACE_SELECT_VALUES: SelectSettingValue<WebUiInterface>[
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const GLOBAL_UPDATE_INTERVAL = {
|
export const GLOBAL_UPDATE_INTERVAL = {
|
||||||
default: 12,
|
default: d(12).hours.inWholeHours,
|
||||||
min: 6,
|
min: d(6).hours.inWholeHours,
|
||||||
max: 24 * 7 * 4, // 1 month
|
max: d(1).months.inWholeHours,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GLOBAL_UPDATE_SKIP_ENTRIES_TO_TRANSLATION: {
|
export const GLOBAL_UPDATE_SKIP_ENTRIES_TO_TRANSLATION: {
|
||||||
@@ -184,21 +184,21 @@ export const GLOBAL_UPDATE_SKIP_ENTRIES_TO_TRANSLATION: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const WEB_UI_UPDATE_INTERVAL = {
|
export const WEB_UI_UPDATE_INTERVAL = {
|
||||||
default: 23,
|
default: d(23).hours.inWholeHours,
|
||||||
min: 1,
|
min: d(1).hours.inWholeHours,
|
||||||
max: 23,
|
max: d(23).hours.inWholeHours,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JWT_ACCESS_TOKEN_EXPIRY = {
|
export const JWT_ACCESS_TOKEN_EXPIRY = {
|
||||||
default: dayjs.duration(5, 'minute').asMinutes(),
|
default: d(5).minutes.inWholeMinutes,
|
||||||
min: dayjs.duration(1, 'minute').asMinutes(),
|
min: d(1).minutes.inWholeMinutes,
|
||||||
max: dayjs.duration(4, 'hour').asMinutes(),
|
max: d(4).hours.inWholeMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const JWT_REFRESH_TOKEN_EXPIRY = {
|
export const JWT_REFRESH_TOKEN_EXPIRY = {
|
||||||
default: dayjs.duration(60, 'day').asDays(),
|
default: d(60).days.inWholeDays,
|
||||||
min: dayjs.duration(1, 'day').asDays(),
|
min: d(1).days.inWholeDays,
|
||||||
max: dayjs.duration(1, 'year').asDays(),
|
max: d(1).years.inWholeDays,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KOREADER_SYNC_PERCENTAGE_TOLERANCE = {
|
export const KOREADER_SYNC_PERCENTAGE_TOLERANCE = {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import ListItemText from '@mui/material/ListItemText';
|
|||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import ListSubheader from '@mui/material/ListSubheader';
|
import ListSubheader from '@mui/material/ListSubheader';
|
||||||
import { t as translate } from 'i18next';
|
import { t as translate } from 'i18next';
|
||||||
import dayjs from 'dayjs';
|
import { d } from 'koration';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
|
import { TextSetting } from '@/base/components/settings/text/TextSetting.tsx';
|
||||||
import { NumberSetting } from '@/base/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/base/components/settings/NumberSetting.tsx';
|
||||||
@@ -279,28 +279,24 @@ export const ServerSettings = () => {
|
|||||||
/>
|
/>
|
||||||
<NumberSetting
|
<NumberSetting
|
||||||
settingTitle={t('settings.server.auth.jwt.access_token_expiry')}
|
settingTitle={t('settings.server.auth.jwt.access_token_expiry')}
|
||||||
settingValue={dayjs.duration(serverSettings.jwtTokenExpiry).humanize()}
|
settingValue={d(serverSettings.jwtTokenExpiry).minutes.humanize()}
|
||||||
value={dayjs.duration(serverSettings.jwtTokenExpiry).asMinutes()}
|
value={d(serverSettings.jwtTokenExpiry).minutes.inWholeMinutes}
|
||||||
valueUnit={t('global.time.minutes.minute_other')}
|
valueUnit={t('global.time.minutes.minute_other')}
|
||||||
defaultValue={JWT_ACCESS_TOKEN_EXPIRY.default}
|
defaultValue={JWT_ACCESS_TOKEN_EXPIRY.default}
|
||||||
minValue={JWT_ACCESS_TOKEN_EXPIRY.min}
|
minValue={JWT_ACCESS_TOKEN_EXPIRY.min}
|
||||||
maxValue={JWT_ACCESS_TOKEN_EXPIRY.max}
|
maxValue={JWT_ACCESS_TOKEN_EXPIRY.max}
|
||||||
handleUpdate={(expiry) =>
|
handleUpdate={(expiry) => updateSetting('jwtTokenExpiry', d(expiry).minutes.toISOString())}
|
||||||
updateSetting('jwtTokenExpiry', dayjs.duration(expiry, 'minute').toISOString())
|
|
||||||
}
|
|
||||||
showSlider
|
showSlider
|
||||||
/>
|
/>
|
||||||
<NumberSetting
|
<NumberSetting
|
||||||
settingTitle={t('settings.server.auth.jwt.refresh_token_expiry')}
|
settingTitle={t('settings.server.auth.jwt.refresh_token_expiry')}
|
||||||
settingValue={dayjs.duration(serverSettings.jwtRefreshExpiry).humanize()}
|
settingValue={d(serverSettings.jwtRefreshExpiry).days.humanize()}
|
||||||
value={dayjs.duration(serverSettings.jwtRefreshExpiry).asDays()}
|
value={d(serverSettings.jwtRefreshExpiry).days.inWholeDays}
|
||||||
valueUnit={t('global.time.days.day_other')}
|
valueUnit={t('global.time.days.day_other')}
|
||||||
defaultValue={JWT_REFRESH_TOKEN_EXPIRY.default}
|
defaultValue={JWT_REFRESH_TOKEN_EXPIRY.default}
|
||||||
minValue={JWT_REFRESH_TOKEN_EXPIRY.min}
|
minValue={JWT_REFRESH_TOKEN_EXPIRY.min}
|
||||||
maxValue={JWT_REFRESH_TOKEN_EXPIRY.max}
|
maxValue={JWT_REFRESH_TOKEN_EXPIRY.max}
|
||||||
handleUpdate={(expiry) =>
|
handleUpdate={(expiry) => updateSetting('jwtRefreshExpiry', d(expiry).days.toISOString())}
|
||||||
updateSetting('jwtRefreshExpiry', dayjs.duration(expiry, 'day').toISOString())
|
|
||||||
}
|
|
||||||
showSlider
|
showSlider
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import { useCallback } from 'react';
|
|||||||
// eslint-disable-next-line import/no-extraneous-dependencies,no-restricted-imports
|
// eslint-disable-next-line import/no-extraneous-dependencies,no-restricted-imports
|
||||||
import { deepmerge } from '@mui/utils';
|
import { deepmerge } from '@mui/utils';
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { PaletteBackgroundChannel } from '@mui/material/styles/createThemeWithVars';
|
|
||||||
import { Palette } from '@vibrant/color';
|
import { Palette } from '@vibrant/color';
|
||||||
|
import { PaletteBackgroundChannel } from 'node_modules/@mui/material/esm/styles/createThemeWithVars';
|
||||||
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
|
||||||
import { AppTheme } from '@/features/theme/services/AppThemes.ts';
|
import { AppTheme } from '@/features/theme/services/AppThemes.ts';
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
|
|||||||
@@ -9,11 +9,12 @@
|
|||||||
import '@/polyfill.manual';
|
import '@/polyfill.manual';
|
||||||
import '@/i18n';
|
import '@/i18n';
|
||||||
import '@/lib/dayjs/Setup.ts';
|
import '@/lib/dayjs/Setup.ts';
|
||||||
|
import '@/lib/koration/Setup.ts';
|
||||||
import '@/index.css';
|
import '@/index.css';
|
||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { App } from '@/App';
|
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
|
import { App } from '@/App';
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.ready.then((registration) => {
|
navigator.serviceWorker.ready.then((registration) => {
|
||||||
|
|||||||
12
src/lib/koration/Setup.ts
Normal file
12
src/lib/koration/Setup.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* 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 { setDurationAdapter } from 'koration';
|
||||||
|
import { DayjsDurationAdapter } from 'koration/adapters/DayjsDurationAdapter';
|
||||||
|
|
||||||
|
setDurationAdapter(new DayjsDurationAdapter());
|
||||||
@@ -24,6 +24,7 @@ import { Client, createClient } from 'graphql-ws';
|
|||||||
import { getMainDefinition } from '@apollo/client/utilities';
|
import { getMainDefinition } from '@apollo/client/utilities';
|
||||||
import { TypePolicies } from '@apollo/client/cache';
|
import { TypePolicies } from '@apollo/client/cache';
|
||||||
import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';
|
import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';
|
||||||
|
import { d } from 'koration';
|
||||||
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
import { BaseClient } from '@/lib/requests/client/BaseClient.ts';
|
||||||
import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts';
|
import { StrictTypedTypePolicies } from '@/lib/graphql/generated/apollo-helpers.ts';
|
||||||
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||||
@@ -271,7 +272,7 @@ export class GraphQLClient extends BaseClient<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createWSClient(lazy: boolean = true): void {
|
private createWSClient(lazy: boolean = true): void {
|
||||||
const heartbeatInterval = 1000 * 20;
|
const heartbeatInterval = d(20).seconds.inWholeMilliseconds;
|
||||||
|
|
||||||
this.wsClient = createClient({
|
this.wsClient = createClient({
|
||||||
lazy,
|
lazy,
|
||||||
@@ -280,7 +281,7 @@ export class GraphQLClient extends BaseClient<
|
|||||||
retryAttempts: Number.MAX_SAFE_INTEGER,
|
retryAttempts: Number.MAX_SAFE_INTEGER,
|
||||||
shouldRetry: () => true,
|
shouldRetry: () => true,
|
||||||
retryWait: async (retries) => {
|
retryWait: async (retries) => {
|
||||||
const delay = Math.min(1000 * 2 ** retries, heartbeatInterval);
|
const delay = Math.min(d(1).seconds.inWholeMilliseconds * 2 ** retries, heartbeatInterval);
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(resolve, delay);
|
setTimeout(resolve, delay);
|
||||||
@@ -301,7 +302,7 @@ export class GraphQLClient extends BaseClient<
|
|||||||
lastHeartbeat = Date.now();
|
lastHeartbeat = Date.now();
|
||||||
});
|
});
|
||||||
|
|
||||||
const checkHeartbeatInterval = heartbeatInterval + 1000 * 30;
|
const checkHeartbeatInterval = heartbeatInterval + d(30).seconds.inWholeMilliseconds;
|
||||||
clearInterval(this.wsClientAliveCheckInterval);
|
clearInterval(this.wsClientAliveCheckInterval);
|
||||||
this.wsClientAliveCheckInterval = setInterval(() => {
|
this.wsClientAliveCheckInterval = setInterval(() => {
|
||||||
const isHeartbeatMissing = Date.now() - lastHeartbeat > checkHeartbeatInterval * 1.1;
|
const isHeartbeatMissing = Date.now() - lastHeartbeat > checkHeartbeatInterval * 1.1;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
|||||||
@@ -6635,6 +6635,11 @@ keyv@^4.5.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
json-buffer "3.0.1"
|
json-buffer "3.0.1"
|
||||||
|
|
||||||
|
koration@0.1.0:
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/koration/-/koration-0.1.0.tgz#149e6021d14f2e8e0034da35de11df4f2768da19"
|
||||||
|
integrity sha512-Ld+r9PRXb4wFCbvz3B4Qoundnu3VaJ9AnWaorK3sqWLWZWSW4YF0vxfujl4zZniUlISYao5L8UpZ4IHHwOVf1w==
|
||||||
|
|
||||||
language-subtag-registry@^0.3.20:
|
language-subtag-registry@^0.3.20:
|
||||||
version "0.3.22"
|
version "0.3.22"
|
||||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
|
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
|
||||||
|
|||||||
Reference in New Issue
Block a user