refactor: use api base url instead of hostname and port
This commit is contained in:
parent
64ea28607a
commit
702169941e
23 changed files with 444 additions and 489 deletions
|
@ -3,7 +3,11 @@ WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
# Using yarn to install dependencies in CI will cause network timeout
|
# Using yarn to install dependencies in CI will cause network timeout
|
||||||
# Refer to https://github.com/date-fns/date-fns/issues/1004
|
# Refer to https://github.com/date-fns/date-fns/issues/1004
|
||||||
RUN yarn config set network-timeout 300000 && yarn && yarn run build
|
RUN yarn config set network-timeout 300000 \
|
||||||
|
&& yarn \
|
||||||
|
&& yarn build \
|
||||||
|
# remove source maps - people like small image
|
||||||
|
&& rm public/*.map
|
||||||
|
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
RUN rm -rf /usr/share/nginx/html/*
|
RUN rm -rf /usr/share/nginx/html/*
|
||||||
|
|
19
package.json
19
package.json
|
@ -39,20 +39,20 @@
|
||||||
"clsx": "^1.1.0",
|
"clsx": "^1.1.0",
|
||||||
"core-js": "^3.6.2",
|
"core-js": "^3.6.2",
|
||||||
"date-fns": "^2.16.0",
|
"date-fns": "^2.16.0",
|
||||||
"framer-motion": "^2.6.5",
|
"framer-motion": "^2.6.7",
|
||||||
"history": "^5.0.0",
|
"history": "^5.0.0",
|
||||||
"immer": "^7.0.8",
|
"immer": "^7.0.8",
|
||||||
"invariant": "^2.2.4",
|
"invariant": "^2.2.4",
|
||||||
"lodash-es": "^4.17.14",
|
"lodash-es": "^4.17.14",
|
||||||
"memoize-one": "^5.1.1",
|
"memoize-one": "^5.1.1",
|
||||||
"modern-normalize": "^0.7.0",
|
"modern-normalize": "^1.0.0",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
"react": "0.0.0-experimental-241c4467e",
|
"react": "0.0.0-experimental-241c4467e",
|
||||||
"react-dom": "0.0.0-experimental-241c4467e",
|
"react-dom": "0.0.0-experimental-241c4467e",
|
||||||
"react-feather": "^2.0.3",
|
"react-feather": "^2.0.3",
|
||||||
"react-icons": "^3.10.0",
|
"react-icons": "^3.10.0",
|
||||||
"react-modal": "^3.11.1",
|
"react-modal": "^3.11.1",
|
||||||
"react-query": "^2.12.1",
|
"react-query": "^2.15.4",
|
||||||
"react-router": "6.0.0-beta.0",
|
"react-router": "6.0.0-beta.0",
|
||||||
"react-router-dom": "6.0.0-beta.0",
|
"react-router-dom": "6.0.0-beta.0",
|
||||||
"react-switch": "^5.0.1",
|
"react-switch": "^5.0.1",
|
||||||
|
@ -83,14 +83,14 @@
|
||||||
"@types/lodash-es": "^4.17.3",
|
"@types/lodash-es": "^4.17.3",
|
||||||
"@types/react": "^16.9.48",
|
"@types/react": "^16.9.48",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||||
"@typescript-eslint/parser": "^4.0.1",
|
"@typescript-eslint/parser": "^4.1.0",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
"babel-eslint": "10.x",
|
"babel-eslint": "10.x",
|
||||||
"babel-loader": "^8.0.5",
|
"babel-loader": "^8.0.5",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"copy-webpack-plugin": "^6.0.4",
|
"copy-webpack-plugin": "^6.0.4",
|
||||||
"css-loader": "^4.2.2",
|
"css-loader": "^4.3.0",
|
||||||
"cssnano": "^4.1.7",
|
"cssnano": "^4.1.7",
|
||||||
"eslint": "^7.6.0",
|
"eslint": "^7.6.0",
|
||||||
"eslint-config-airbnb-base": "^14.1.0",
|
"eslint-config-airbnb-base": "^14.1.0",
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
"eslint-import-resolver-webpack": "^0.12.2",
|
"eslint-import-resolver-webpack": "^0.12.2",
|
||||||
"eslint-plugin-flowtype": "^5.1.0",
|
"eslint-plugin-flowtype": "^5.1.0",
|
||||||
"eslint-plugin-import": "^2.22.0",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"eslint-plugin-jest": "^23.20.0",
|
"eslint-plugin-jest": "^24.0.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.3.1",
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||||
"eslint-plugin-react": "^7.20.6",
|
"eslint-plugin-react": "^7.20.6",
|
||||||
"eslint-plugin-react-hooks": "^4.0.8",
|
"eslint-plugin-react-hooks": "^4.0.8",
|
||||||
|
@ -108,13 +108,14 @@
|
||||||
"fork-ts-checker-notifier-webpack-plugin": "^3.0.0",
|
"fork-ts-checker-notifier-webpack-plugin": "^3.0.0",
|
||||||
"fork-ts-checker-webpack-plugin": "^5.0.14",
|
"fork-ts-checker-webpack-plugin": "^5.0.14",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"husky": "^4.0.0",
|
"husky": "^4.3.0",
|
||||||
"lint-staged": "^10.2.13",
|
"lint-staged": "^10.2.13",
|
||||||
"mini-css-extract-plugin": "^0.11.0",
|
"mini-css-extract-plugin": "^0.11.0",
|
||||||
|
"postcss": "^7.0.32",
|
||||||
"postcss-custom-media": "^7.0.8",
|
"postcss-custom-media": "^7.0.8",
|
||||||
"postcss-extend-rule": "^3.0.0",
|
"postcss-extend-rule": "^3.0.0",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-import": "^12.0.1",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^4.0.0",
|
||||||
"postcss-nested": "^4.2.3",
|
"postcss-nested": "^4.2.3",
|
||||||
"postcss-simple-vars": "^5.0.2",
|
"postcss-simple-vars": "^5.0.2",
|
||||||
"prettier": "^2.1.1",
|
"prettier": "^2.1.1",
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { getURLAndInit } from '../misc/request-helper';
|
|
||||||
|
|
||||||
const endpoint = '/configs';
|
|
||||||
|
|
||||||
export async function fetchConfigs(apiConfig) {
|
|
||||||
const { url, init } = getURLAndInit(apiConfig);
|
|
||||||
return await fetch(url + endpoint, init);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO support PUT /configs
|
|
||||||
// req body
|
|
||||||
// { Path: string }
|
|
||||||
|
|
||||||
function configsPatchWorkaround(o) {
|
|
||||||
// backward compatibility for older clash using `socket-port`
|
|
||||||
if ('socks-port' in o) {
|
|
||||||
o['socket-port'] = o['socks-port'];
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateConfigs(apiConfig, o) {
|
|
||||||
const { url, init } = getURLAndInit(apiConfig);
|
|
||||||
return await fetch(url + endpoint, {
|
|
||||||
...init,
|
|
||||||
method: 'PATCH',
|
|
||||||
// mode: 'cors',
|
|
||||||
body: JSON.stringify(configsPatchWorkaround(o))
|
|
||||||
});
|
|
||||||
}
|
|
31
src/api/configs.ts
Normal file
31
src/api/configs.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { getURLAndInit } from 'src/misc/request-helper';
|
||||||
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
|
const endpoint = '/configs';
|
||||||
|
|
||||||
|
export async function fetchConfigs(apiConfig: ClashAPIConfig) {
|
||||||
|
const { url, init } = getURLAndInit(apiConfig);
|
||||||
|
return await fetch(url + endpoint, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO support PUT /configs
|
||||||
|
// req body
|
||||||
|
// { Path: string }
|
||||||
|
|
||||||
|
type ClashConfigPartial = { 'socks-port'?: unknown };
|
||||||
|
function configsPatchWorkaround(o: ClashConfigPartial) {
|
||||||
|
// backward compatibility for older clash using `socket-port`
|
||||||
|
if ('socks-port' in o) {
|
||||||
|
o['socket-port'] = o['socks-port'];
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateConfigs(
|
||||||
|
apiConfig: ClashAPIConfig,
|
||||||
|
o: ClashConfigPartial
|
||||||
|
) {
|
||||||
|
const { url, init } = getURLAndInit(apiConfig);
|
||||||
|
const body = JSON.stringify(configsPatchWorkaround(o));
|
||||||
|
return await fetch(url + endpoint, { ...init, body, method: 'PATCH' });
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
import { getURLAndInit } from '../misc/request-helper';
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
|
import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper';
|
||||||
|
|
||||||
const endpoint = '/connections';
|
const endpoint = '/connections';
|
||||||
|
|
||||||
|
@ -8,31 +10,31 @@ const subscribers = [];
|
||||||
// see also https://github.com/Dreamacro/clash/blob/dev/constant/metadata.go#L41
|
// see also https://github.com/Dreamacro/clash/blob/dev/constant/metadata.go#L41
|
||||||
type UUID = string;
|
type UUID = string;
|
||||||
type ConnectionItem = {
|
type ConnectionItem = {
|
||||||
id: UUID,
|
id: UUID;
|
||||||
metadata: {
|
metadata: {
|
||||||
network: 'tcp' | 'udp',
|
network: 'tcp' | 'udp';
|
||||||
type: 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown',
|
type: 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown';
|
||||||
sourceIP: string,
|
sourceIP: string;
|
||||||
destinationIP: string,
|
destinationIP: string;
|
||||||
sourcePort: string,
|
sourcePort: string;
|
||||||
destinationPort: string,
|
destinationPort: string;
|
||||||
host: string,
|
host: string;
|
||||||
},
|
};
|
||||||
upload: number,
|
upload: number;
|
||||||
download: number,
|
download: number;
|
||||||
// e.g. "2019-11-30T22:48:13.416668+08:00",
|
// e.g. "2019-11-30T22:48:13.416668+08:00",
|
||||||
start: string,
|
start: string;
|
||||||
chains: Array<string>,
|
chains: Array<string>;
|
||||||
// e.g. 'Match', 'DomainKeyword'
|
// e.g. 'Match', 'DomainKeyword'
|
||||||
rule: string,
|
rule: string;
|
||||||
};
|
};
|
||||||
type ConnectionsData = {
|
type ConnectionsData = {
|
||||||
downloadTotal: number,
|
downloadTotal: number;
|
||||||
uploadTotal: number,
|
uploadTotal: number;
|
||||||
connections: Array<ConnectionItem>,
|
connections: Array<ConnectionItem>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function appendData(s) {
|
function appendData(s: string) {
|
||||||
let o: ConnectionsData;
|
let o: ConnectionsData;
|
||||||
try {
|
try {
|
||||||
o = JSON.parse(s);
|
o = JSON.parse(s);
|
||||||
|
@ -43,33 +45,25 @@ function appendData(s) {
|
||||||
subscribers.forEach((f) => f(o));
|
subscribers.forEach((f) => f(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWsUrl(apiConfig) {
|
type UnsubscribeFn = () => void;
|
||||||
const { hostname, port, secret } = apiConfig;
|
|
||||||
let qs = '';
|
|
||||||
if (typeof secret === 'string' && secret !== '') {
|
|
||||||
qs += '?token=' + encodeURIComponent(secret);
|
|
||||||
}
|
|
||||||
return `ws://${hostname}:${port}${endpoint}${qs}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let wsState;
|
let wsState: number;
|
||||||
function fetchData(apiConfig, listener) {
|
export function fetchData(
|
||||||
|
apiConfig: ClashAPIConfig,
|
||||||
|
listener: unknown
|
||||||
|
): UnsubscribeFn | void {
|
||||||
if (fetched || wsState === 1) {
|
if (fetched || wsState === 1) {
|
||||||
if (listener) return subscribe(listener);
|
if (listener) return subscribe(listener);
|
||||||
}
|
}
|
||||||
wsState = 1;
|
wsState = 1;
|
||||||
const url = getWsUrl(apiConfig);
|
const url = buildWebSocketURL(apiConfig, endpoint);
|
||||||
const ws = new WebSocket(url);
|
const ws = new WebSocket(url);
|
||||||
ws.addEventListener('error', function (_ev) {
|
ws.addEventListener('error', () => (wsState = 3));
|
||||||
wsState = 3;
|
ws.addEventListener('message', (event) => appendData(event.data));
|
||||||
});
|
|
||||||
ws.addEventListener('message', function (event) {
|
|
||||||
appendData(event.data);
|
|
||||||
});
|
|
||||||
if (listener) return subscribe(listener);
|
if (listener) return subscribe(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscribe(listener) {
|
function subscribe(listener: unknown): UnsubscribeFn {
|
||||||
subscribers.push(listener);
|
subscribers.push(listener);
|
||||||
return function unsubscribe() {
|
return function unsubscribe() {
|
||||||
const idx = subscribers.indexOf(listener);
|
const idx = subscribers.indexOf(listener);
|
||||||
|
@ -77,20 +71,18 @@ function subscribe(listener) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function closeAllConnections(apiConfig) {
|
export async function closeAllConnections(apiConfig: ClashAPIConfig) {
|
||||||
const { url, init } = getURLAndInit(apiConfig);
|
const { url, init } = getURLAndInit(apiConfig);
|
||||||
return await fetch(url + endpoint, { ...init, method: 'DELETE' });
|
return await fetch(url + endpoint, { ...init, method: 'DELETE' });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchConns(apiConfig) {
|
export async function fetchConns(apiConfig: ClashAPIConfig) {
|
||||||
const { url, init } = getURLAndInit(apiConfig);
|
const { url, init } = getURLAndInit(apiConfig);
|
||||||
return await fetch(url + endpoint, { ...init });
|
return await fetch(url + endpoint, { ...init });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function closeConnById(apiConfig, id) {
|
export async function closeConnById(apiConfig: ClashAPIConfig, id: string) {
|
||||||
const { url: baseURL, init } = getURLAndInit(apiConfig);
|
const { url: baseURL, init } = getURLAndInit(apiConfig);
|
||||||
const url = `${baseURL}${endpoint}/${id}`;
|
const url = `${baseURL}${endpoint}/${id}`;
|
||||||
return await fetch(url, { ...init, method: 'DELETE' });
|
return await fetch(url, { ...init, method: 'DELETE' });
|
||||||
}
|
}
|
||||||
|
|
||||||
export { fetchData, closeAllConnections };
|
|
|
@ -1,4 +1,16 @@
|
||||||
import { getURLAndInit } from '../misc/request-helper';
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
|
import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper';
|
||||||
|
|
||||||
|
type LogsAPIConfig = ClashAPIConfig & { logLevel: string };
|
||||||
|
type LogEntry = {
|
||||||
|
time?: string;
|
||||||
|
id?: string;
|
||||||
|
even?: boolean;
|
||||||
|
// and some other props
|
||||||
|
};
|
||||||
|
type AppendLogFn = (x: LogEntry) => void;
|
||||||
|
|
||||||
const endpoint = '/logs';
|
const endpoint = '/logs';
|
||||||
const textDecoder = new TextDecoder('utf-8');
|
const textDecoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
@ -10,8 +22,8 @@ let even = false;
|
||||||
let fetched = false;
|
let fetched = false;
|
||||||
let decoded = '';
|
let decoded = '';
|
||||||
|
|
||||||
function appendData(s, callback) {
|
function appendData(s: string, callback: AppendLogFn) {
|
||||||
let o;
|
let o: LogEntry;
|
||||||
try {
|
try {
|
||||||
o = JSON.parse(s);
|
o = JSON.parse(s);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -23,12 +35,12 @@ function appendData(s, callback) {
|
||||||
const time = now.toLocaleString('zh-Hans');
|
const time = now.toLocaleString('zh-Hans');
|
||||||
// mutate input param in place intentionally
|
// mutate input param in place intentionally
|
||||||
o.time = time;
|
o.time = time;
|
||||||
o.id = now - 0 + getRandomStr();
|
o.id = +now - 0 + getRandomStr();
|
||||||
o.even = even = !even;
|
o.even = even = !even;
|
||||||
callback(o);
|
callback(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pump(reader, appendLog) {
|
function pump(reader: ReadableStreamDefaultReader, appendLog: AppendLogFn) {
|
||||||
return reader.read().then(({ done, value }) => {
|
return reader.read().then(({ done, value }) => {
|
||||||
const str = textDecoder.decode(value, { stream: !done });
|
const str = textDecoder.decode(value, { stream: !done });
|
||||||
decoded += str;
|
decoded += str;
|
||||||
|
@ -56,31 +68,20 @@ function pump(reader, appendLog) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiConfigSnapshot = {};
|
let apiConfigSnapshot: LogsAPIConfig;
|
||||||
let controller;
|
let controller: AbortController;
|
||||||
|
|
||||||
function getWsUrl(apiConfig) {
|
|
||||||
const { hostname, port, secret, logLevel } = apiConfig;
|
|
||||||
let qs = '?level=' + logLevel;
|
|
||||||
if (typeof secret === 'string' && secret !== '') {
|
|
||||||
qs += '&token=' + encodeURIComponent(secret);
|
|
||||||
}
|
|
||||||
return `ws://${hostname}:${port}${endpoint}${qs}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1 OPEN
|
// 1 OPEN
|
||||||
// other value CLOSED
|
// other value CLOSED
|
||||||
// similar to ws readyState but not the same
|
// similar to ws readyState but not the same
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
|
||||||
let wsState;
|
let wsState: number;
|
||||||
function fetchLogs(apiConfig, appendLog) {
|
export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
|
||||||
if (fetched || wsState === 1) return;
|
if (fetched || wsState === 1) return;
|
||||||
wsState = 1;
|
wsState = 1;
|
||||||
const url = getWsUrl(apiConfig);
|
const url = buildWebSocketURL(apiConfig, endpoint);
|
||||||
const ws = new WebSocket(url);
|
const ws = new WebSocket(url);
|
||||||
ws.addEventListener('error', function (_ev) {
|
ws.addEventListener('error', () => (wsState = 3));
|
||||||
wsState = 3;
|
|
||||||
});
|
|
||||||
ws.addEventListener('close', function (_ev) {
|
ws.addEventListener('close', function (_ev) {
|
||||||
wsState = 3;
|
wsState = 3;
|
||||||
fetchLogsWithFetch(apiConfig, appendLog);
|
fetchLogsWithFetch(apiConfig, appendLog);
|
||||||
|
@ -90,11 +91,10 @@ function fetchLogs(apiConfig, appendLog) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchLogsWithFetch(apiConfig, appendLog) {
|
function fetchLogsWithFetch(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
|
||||||
if (
|
if (
|
||||||
controller &&
|
controller &&
|
||||||
(apiConfigSnapshot.hostname !== apiConfig.hostname ||
|
(apiConfigSnapshot.baseURL !== apiConfig.baseURL ||
|
||||||
apiConfigSnapshot.port !== apiConfig.port ||
|
|
||||||
apiConfigSnapshot.secret !== apiConfig.secret ||
|
apiConfigSnapshot.secret !== apiConfig.secret ||
|
||||||
apiConfigSnapshot.logLevel !== apiConfig.logLevel)
|
apiConfigSnapshot.logLevel !== apiConfig.logLevel)
|
||||||
) {
|
) {
|
||||||
|
@ -104,11 +104,7 @@ function fetchLogsWithFetch(apiConfig, appendLog) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fetched = true;
|
fetched = true;
|
||||||
|
apiConfigSnapshot = { ...apiConfig };
|
||||||
apiConfigSnapshot.hostname = apiConfig.hostname;
|
|
||||||
apiConfigSnapshot.port = apiConfig.port;
|
|
||||||
apiConfigSnapshot.secret = apiConfig.secret;
|
|
||||||
apiConfigSnapshot.logLevel = apiConfig.logLevel;
|
|
||||||
|
|
||||||
controller = new AbortController();
|
controller = new AbortController();
|
||||||
const signal = controller.signal;
|
const signal = controller.signal;
|
||||||
|
@ -131,5 +127,3 @@ function fetchLogsWithFetch(apiConfig, appendLog) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { fetchLogs };
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { getURLAndInit } from '../misc/request-helper';
|
import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper';
|
||||||
const endpoint = '/traffic';
|
const endpoint = '/traffic';
|
||||||
const textDecoder = new TextDecoder('utf-8');
|
const textDecoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
@ -69,15 +69,6 @@ function pump(reader) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWsUrl(apiConfig) {
|
|
||||||
const { hostname, port, secret } = apiConfig;
|
|
||||||
let qs = '';
|
|
||||||
if (typeof secret === 'string' && secret !== '') {
|
|
||||||
qs += '?token=' + encodeURIComponent(secret);
|
|
||||||
}
|
|
||||||
return `ws://${hostname}:${port}${endpoint}${qs}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1 OPEN
|
// 1 OPEN
|
||||||
// other value CLOSED
|
// other value CLOSED
|
||||||
// similar to ws readyState but not the same
|
// similar to ws readyState but not the same
|
||||||
|
@ -86,7 +77,7 @@ let wsState;
|
||||||
function fetchData(apiConfig) {
|
function fetchData(apiConfig) {
|
||||||
if (fetched || wsState === 1) return traffic;
|
if (fetched || wsState === 1) return traffic;
|
||||||
wsState = 1;
|
wsState = 1;
|
||||||
const url = getWsUrl(apiConfig);
|
const url = buildWebSocketURL(apiConfig, endpoint);
|
||||||
const ws = new WebSocket(url);
|
const ws = new WebSocket(url);
|
||||||
ws.addEventListener('error', function (_ev) {
|
ws.addEventListener('error', function (_ev) {
|
||||||
wsState = 3;
|
wsState = 3;
|
||||||
|
|
|
@ -10,6 +10,7 @@ const rootEl = document.getElementById('app');
|
||||||
|
|
||||||
Modal.setAppElement(rootEl);
|
Modal.setAppElement(rootEl);
|
||||||
|
|
||||||
|
// ReactDOM.render(<Root />, rootEl);
|
||||||
const { createRoot } = ReactDOM;
|
const { createRoot } = ReactDOM;
|
||||||
const root = createRoot(rootEl);
|
const root = createRoot(rootEl);
|
||||||
root.render(<Root />);
|
root.render(<Root />);
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { getClashAPIConfig, updateClashAPIConfig } from '../store/app';
|
|
||||||
import s0 from './APIConfig.module.css';
|
|
||||||
import Button from './Button';
|
|
||||||
import Field from './Field';
|
|
||||||
import { connect } from './StateProvider';
|
|
||||||
import SvgYacd from './SvgYacd';
|
|
||||||
|
|
||||||
const { useState, useEffect, useRef, useCallback } = React;
|
|
||||||
|
|
||||||
const mapState = (s) => ({
|
|
||||||
apiConfig: getClashAPIConfig(s),
|
|
||||||
});
|
|
||||||
|
|
||||||
function APIConfig({ apiConfig, dispatch }) {
|
|
||||||
const [hostname, setHostname] = useState(apiConfig.hostname);
|
|
||||||
const [port, setPort] = useState(apiConfig.port);
|
|
||||||
const [secret, setSecret] = useState(apiConfig.secret);
|
|
||||||
|
|
||||||
const userTouchedFlagRef = useRef(false);
|
|
||||||
const contentEl = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
contentEl.current.focus();
|
|
||||||
|
|
||||||
async function detectApiServer() {
|
|
||||||
// API server probing
|
|
||||||
// likely the current page url share the same base url with the API
|
|
||||||
// server
|
|
||||||
try {
|
|
||||||
const res = await fetch('/');
|
|
||||||
const data = await res.json();
|
|
||||||
if (data.hello === 'clash' && userTouchedFlagRef.current === false) {
|
|
||||||
const { hostname, port } = window.location;
|
|
||||||
setHostname(hostname);
|
|
||||||
setPort(port);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
detectApiServer();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleInputOnChange = useCallback((e) => {
|
|
||||||
userTouchedFlagRef.current = true;
|
|
||||||
const target = e.target;
|
|
||||||
const { name } = target;
|
|
||||||
const value = target.value;
|
|
||||||
switch (name) {
|
|
||||||
case 'port':
|
|
||||||
setPort(value);
|
|
||||||
break;
|
|
||||||
case 'hostname':
|
|
||||||
setHostname(value);
|
|
||||||
break;
|
|
||||||
case 'secret':
|
|
||||||
setSecret(value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`unknown input name ${name}`);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const updateConfig = useCallback(() => {
|
|
||||||
dispatch(updateClashAPIConfig({ hostname, port, secret }));
|
|
||||||
}, [hostname, port, secret, dispatch]);
|
|
||||||
|
|
||||||
const handleContentOnKeyDown = useCallback(
|
|
||||||
(e) => {
|
|
||||||
// enter keyCode is 13
|
|
||||||
if (e.keyCode !== 13) return;
|
|
||||||
updateConfig();
|
|
||||||
},
|
|
||||||
[updateConfig]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
||||||
<div className={s0.root} ref={contentEl} onKeyDown={handleContentOnKeyDown}>
|
|
||||||
<div className={s0.header}>
|
|
||||||
<div className={s0.icon}>
|
|
||||||
<SvgYacd width={160} height={160} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s0.body}>
|
|
||||||
<div className={s0.hostnamePort}>
|
|
||||||
<div>
|
|
||||||
<Field
|
|
||||||
id="hostname"
|
|
||||||
name="hostname"
|
|
||||||
label="Hostname"
|
|
||||||
type="text"
|
|
||||||
value={hostname}
|
|
||||||
onChange={handleInputOnChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Field
|
|
||||||
id="port"
|
|
||||||
name="port"
|
|
||||||
label="Port"
|
|
||||||
type="number"
|
|
||||||
value={port}
|
|
||||||
onChange={handleInputOnChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Field
|
|
||||||
id="secret"
|
|
||||||
name="secret"
|
|
||||||
label="Secret(optional)"
|
|
||||||
value={secret}
|
|
||||||
type="text"
|
|
||||||
onChange={handleInputOnChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s0.footer}>
|
|
||||||
<Button label="Confirm" onClick={updateConfig} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapState)(APIConfig);
|
|
|
@ -20,7 +20,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
padding: 30px 0 10px;
|
padding: 30px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hostnamePort {
|
.hostnamePort {
|
||||||
|
@ -37,8 +37,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
height: 20px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #ff8b8b;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 30px 0 10px;
|
padding: 5px 0 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
116
src/components/APIConfig.tsx
Normal file
116
src/components/APIConfig.tsx
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { fetchConfigs } from 'src/api/configs';
|
||||||
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
|
import { getClashAPIConfig, updateClashAPIConfig } from '../store/app';
|
||||||
|
import s0 from './APIConfig.module.css';
|
||||||
|
import Button from './Button';
|
||||||
|
import Field from './Field';
|
||||||
|
import { connect } from './StateProvider';
|
||||||
|
import SvgYacd from './SvgYacd';
|
||||||
|
|
||||||
|
const { useState, useRef, useCallback } = React;
|
||||||
|
const Ok = 0;
|
||||||
|
|
||||||
|
const mapState = (s) => ({
|
||||||
|
apiConfig: getClashAPIConfig(s),
|
||||||
|
});
|
||||||
|
|
||||||
|
function APIConfig({ apiConfig, dispatch }) {
|
||||||
|
const [baseURL, setBaseURL] = useState(apiConfig.baseURL);
|
||||||
|
const [secret, setSecret] = useState(apiConfig.secret);
|
||||||
|
const [errMsg, setErrMsg] = useState('');
|
||||||
|
|
||||||
|
const userTouchedFlagRef = useRef(false);
|
||||||
|
const contentEl = useRef(null);
|
||||||
|
|
||||||
|
const handleInputOnChange = useCallback((e) => {
|
||||||
|
userTouchedFlagRef.current = true;
|
||||||
|
setErrMsg('');
|
||||||
|
const target = e.target;
|
||||||
|
const { name } = target;
|
||||||
|
const value = target.value;
|
||||||
|
switch (name) {
|
||||||
|
case 'baseURL':
|
||||||
|
setBaseURL(value);
|
||||||
|
break;
|
||||||
|
case 'secret':
|
||||||
|
setSecret(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`unknown input name ${name}`);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onConfirm = useCallback(() => {
|
||||||
|
verify({ baseURL, secret }).then((ret) => {
|
||||||
|
if (ret[0] !== Ok) {
|
||||||
|
setErrMsg(ret[1]);
|
||||||
|
} else {
|
||||||
|
dispatch(updateClashAPIConfig({ baseURL, secret }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [baseURL, secret, dispatch]);
|
||||||
|
|
||||||
|
const handleContentOnKeyDown = useCallback(
|
||||||
|
(e) => {
|
||||||
|
if (e.key !== 'Enter') return;
|
||||||
|
onConfirm();
|
||||||
|
},
|
||||||
|
[onConfirm]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
||||||
|
<div className={s0.root} ref={contentEl} onKeyDown={handleContentOnKeyDown}>
|
||||||
|
<div className={s0.header}>
|
||||||
|
<div className={s0.icon}>
|
||||||
|
<SvgYacd width={160} height={160} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s0.body}>
|
||||||
|
<div className={s0.hostnamePort}>
|
||||||
|
<Field
|
||||||
|
id="baseURL"
|
||||||
|
name="baseURL"
|
||||||
|
label="API Base URL"
|
||||||
|
type="text"
|
||||||
|
value={baseURL}
|
||||||
|
onChange={handleInputOnChange}
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
id="secret"
|
||||||
|
name="secret"
|
||||||
|
label="Secret(optional)"
|
||||||
|
value={secret}
|
||||||
|
type="text"
|
||||||
|
onChange={handleInputOnChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s0.error}>{errMsg ? errMsg : null}</div>
|
||||||
|
<div className={s0.footer}>
|
||||||
|
<Button label="Confirm" onClick={onConfirm} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapState)(APIConfig);
|
||||||
|
|
||||||
|
async function verify(apiConfig: ClashAPIConfig): Promise<[number, string?]> {
|
||||||
|
try {
|
||||||
|
new URL(apiConfig.baseURL);
|
||||||
|
} catch (e) {
|
||||||
|
return [1, 'Invalid URL'];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await fetchConfigs(apiConfig);
|
||||||
|
if (res.status > 399) {
|
||||||
|
return [1, res.statusText];
|
||||||
|
}
|
||||||
|
return [Ok];
|
||||||
|
} catch (e) {
|
||||||
|
return [1, 'Failed to connect'];
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ import cx from 'clsx';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ChevronDown } from 'react-feather';
|
import { ChevronDown } from 'react-feather';
|
||||||
|
|
||||||
import { keyCodes } from '../misc/keycode';
|
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import s from './CollapsibleSectionHeader.module.css';
|
import s from './CollapsibleSectionHeader.module.css';
|
||||||
import { SectionNameType } from './shared/Basic';
|
import { SectionNameType } from './shared/Basic';
|
||||||
|
@ -19,7 +18,7 @@ export default function Header({ name, type, toggle, isOpen, qty }: Props) {
|
||||||
const handleKeyDown = React.useCallback(
|
const handleKeyDown = React.useCallback(
|
||||||
(e: React.KeyboardEvent) => {
|
(e: React.KeyboardEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.keyCode === keyCodes.Enter || e.keyCode === keyCodes.Space) {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
toggle();
|
toggle();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
input {
|
input {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
/* background-color: var(--color-input-bg); */
|
|
||||||
background-image: none;
|
background-image: none;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -15,7 +14,7 @@
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 0 8px;
|
padding: 0 4px;
|
||||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
&:focus {
|
&:focus {
|
||||||
|
@ -25,10 +24,11 @@
|
||||||
|
|
||||||
label {
|
label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 8px;
|
left: 5px;
|
||||||
bottom: 22px;
|
bottom: 22px;
|
||||||
transition: transform 150ms ease-in-out;
|
transition: transform 150ms ease-in-out;
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
|
font-size: 0.9em;
|
||||||
&.floatAbove {
|
&.floatAbove {
|
||||||
transform: scale(0.75) translateY(-25px);
|
transform: scale(0.75) translateY(-25px);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import ContentHeader from './ContentHeader';
|
||||||
import s0 from './Logs.module.css';
|
import s0 from './Logs.module.css';
|
||||||
import LogSearch from './LogSearch';
|
import LogSearch from './LogSearch';
|
||||||
import { connect } from './StateProvider';
|
import { connect } from './StateProvider';
|
||||||
// import { useStoreState, useActions } from '../misc/store';
|
|
||||||
import SvgYacd from './SvgYacd';
|
import SvgYacd from './SvgYacd';
|
||||||
|
|
||||||
const { useCallback, memo, useEffect } = React;
|
const { useCallback, memo, useEffect } = React;
|
||||||
|
@ -64,7 +63,6 @@ const Row = memo(({ index, style, data }) => {
|
||||||
}, areEqual);
|
}, areEqual);
|
||||||
|
|
||||||
function Logs({ dispatch, logLevel, apiConfig, logs }) {
|
function Logs({ dispatch, logLevel, apiConfig, logs }) {
|
||||||
const { hostname, port, secret } = apiConfig;
|
|
||||||
const appendLogInternal = useCallback(
|
const appendLogInternal = useCallback(
|
||||||
(log) => {
|
(log) => {
|
||||||
dispatch(appendLog(log));
|
dispatch(appendLog(log));
|
||||||
|
@ -72,8 +70,8 @@ function Logs({ dispatch, logLevel, apiConfig, logs }) {
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchLogs({ hostname, port, secret, logLevel }, appendLogInternal);
|
fetchLogs({ ...apiConfig, logLevel }, appendLogInternal);
|
||||||
}, [hostname, port, secret, logLevel, appendLogInternal]);
|
}, [apiConfig, logLevel, appendLogInternal]);
|
||||||
const [refLogsContainer, containerHeight] = useRemainingViewPortHeight();
|
const [refLogsContainer, containerHeight] = useRemainingViewPortHeight();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
const headersCommon = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
};
|
|
||||||
|
|
||||||
export function genCommonHeaders({ secret }) {
|
|
||||||
const h = { ...headersCommon };
|
|
||||||
if (secret) {
|
|
||||||
h['Authorization'] = `Bearer ${secret}`;
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAPIBaseURL({ hostname, port }) {
|
|
||||||
return `http://${hostname}:${port}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getURLAndInit({ hostname, port, secret }) {
|
|
||||||
const baseURL = getAPIBaseURL({ hostname, port });
|
|
||||||
const headers = genCommonHeaders({ secret });
|
|
||||||
return {
|
|
||||||
url: baseURL,
|
|
||||||
init: { headers }
|
|
||||||
};
|
|
||||||
}
|
|
31
src/misc/request-helper.ts
Normal file
31
src/misc/request-helper.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { trimTrailingSlash } from 'src/misc/utils';
|
||||||
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
|
const headersCommon = { 'Content-Type': 'application/json' };
|
||||||
|
|
||||||
|
function genCommonHeaders({ secret }: { secret?: string }) {
|
||||||
|
const h = { ...headersCommon };
|
||||||
|
if (secret) {
|
||||||
|
h['Authorization'] = `Bearer ${secret}`;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getURLAndInit({ baseURL, secret }: ClashAPIConfig) {
|
||||||
|
const headers = genCommonHeaders({ secret });
|
||||||
|
return {
|
||||||
|
url: baseURL,
|
||||||
|
init: { headers },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildWebSocketURL(apiConfig: ClashAPIConfig, endpoint: string) {
|
||||||
|
const { baseURL, secret } = apiConfig;
|
||||||
|
let qs = '';
|
||||||
|
if (typeof secret === 'string' && secret !== '') {
|
||||||
|
qs += '?token=' + encodeURIComponent(secret);
|
||||||
|
}
|
||||||
|
const url = new URL(baseURL);
|
||||||
|
url.protocol === 'https:' ? (url.protocol = 'wss:') : (url.protocol = 'ws:');
|
||||||
|
return `${trimTrailingSlash(url.href)}${endpoint}${qs}`;
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
export function throttle(fn, timeout) {
|
|
||||||
let pending = false;
|
|
||||||
|
|
||||||
return (...args) => {
|
|
||||||
if (!pending) {
|
|
||||||
pending = true;
|
|
||||||
fn(...args);
|
|
||||||
setTimeout(() => {
|
|
||||||
pending = false;
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function debounce(fn, timeout) {
|
|
||||||
let timeoutId;
|
|
||||||
return (...args) => {
|
|
||||||
if (timeoutId) clearTimeout(timeoutId);
|
|
||||||
timeoutId = setTimeout(() => {
|
|
||||||
fn(...args);
|
|
||||||
}, timeout);
|
|
||||||
};
|
|
||||||
}
|
|
33
src/misc/utils.ts
Normal file
33
src/misc/utils.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
export function throttle<T extends any[]>(
|
||||||
|
fn: (...args: T) => unknown,
|
||||||
|
timeout: number
|
||||||
|
) {
|
||||||
|
let pending = false;
|
||||||
|
|
||||||
|
return (...args: T) => {
|
||||||
|
if (!pending) {
|
||||||
|
pending = true;
|
||||||
|
fn(...args);
|
||||||
|
setTimeout(() => {
|
||||||
|
pending = false;
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function debounce<T extends any[]>(
|
||||||
|
fn: (...args: T) => unknown,
|
||||||
|
timeout: number
|
||||||
|
) {
|
||||||
|
let timeoutId: number;
|
||||||
|
return (...args: T) => {
|
||||||
|
if (timeoutId) clearTimeout(timeoutId);
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
fn(...args);
|
||||||
|
}, timeout);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trimTrailingSlash(s: string) {
|
||||||
|
return s.replace(/\/$/, '');
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
import { clearState, loadState, saveState } from '../misc/storage';
|
import { clearState, loadState, saveState } from '../misc/storage';
|
||||||
import { debounce } from '../misc/utils';
|
import { debounce, trimTrailingSlash } from '../misc/utils';
|
||||||
import { fetchConfigs } from './configs';
|
import { fetchConfigs } from './configs';
|
||||||
import { closeModal } from './modals';
|
import { closeModal } from './modals';
|
||||||
|
|
||||||
export const getClashAPIConfig = (s) => s.app.clashAPIConfig;
|
export const getClashAPIConfig = (s) => {
|
||||||
|
const idx = s.app.selectedClashAPIConfigIndex;
|
||||||
|
return s.app.clashAPIConfigs[idx];
|
||||||
|
};
|
||||||
export const getTheme = (s) => s.app.theme;
|
export const getTheme = (s) => s.app.theme;
|
||||||
export const getSelectedChartStyleIndex = (s) => s.app.selectedChartStyleIndex;
|
export const getSelectedChartStyleIndex = (s) => s.app.selectedChartStyleIndex;
|
||||||
export const getLatencyTestUrl = (s) => s.app.latencyTestUrl;
|
export const getLatencyTestUrl = (s) => s.app.latencyTestUrl;
|
||||||
|
@ -14,12 +17,11 @@ export const getAutoCloseOldConns = (s) => s.app.autoCloseOldConns;
|
||||||
|
|
||||||
const saveStateDebounced = debounce(saveState, 600);
|
const saveStateDebounced = debounce(saveState, 600);
|
||||||
|
|
||||||
export function updateClashAPIConfig({ hostname: iHostname, port, secret }) {
|
export function updateClashAPIConfig({ baseURL, secret }) {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const hostname = iHostname.trim().replace(/^http(s):\/\//, '');
|
const clashAPIConfig = { baseURL, secret };
|
||||||
const clashAPIConfig = { hostname, port, secret };
|
|
||||||
dispatch('appUpdateClashAPIConfig', (s) => {
|
dispatch('appUpdateClashAPIConfig', (s) => {
|
||||||
s.app.clashAPIConfig = clashAPIConfig;
|
s.app.clashAPIConfigs[0] = clashAPIConfig;
|
||||||
});
|
});
|
||||||
// side effect
|
// side effect
|
||||||
saveState(getState().app);
|
saveState(getState().app);
|
||||||
|
@ -92,13 +94,15 @@ export function updateCollapsibleIsOpen(prefix, name, v) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultClashAPIConfig = {
|
||||||
|
baseURL: 'http://127.0.0.1:7892',
|
||||||
|
secret: '',
|
||||||
|
};
|
||||||
// type Theme = 'light' | 'dark';
|
// type Theme = 'light' | 'dark';
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
clashAPIConfig: {
|
selectedClashAPIConfigIndex: 0,
|
||||||
hostname: '127.0.0.1',
|
clashAPIConfigs: [defaultClashAPIConfig],
|
||||||
port: '7892',
|
|
||||||
secret: '',
|
|
||||||
},
|
|
||||||
latencyTestUrl: 'http://www.gstatic.com/generate_204',
|
latencyTestUrl: 'http://www.gstatic.com/generate_204',
|
||||||
selectedChartStyleIndex: 0,
|
selectedChartStyleIndex: 0,
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
|
@ -126,18 +130,24 @@ function parseConfigQueryString() {
|
||||||
export function initialState() {
|
export function initialState() {
|
||||||
let s = loadState();
|
let s = loadState();
|
||||||
s = { ...defaultState, ...s };
|
s = { ...defaultState, ...s };
|
||||||
// TODO flat clashAPIConfig?
|
|
||||||
|
|
||||||
const query = parseConfigQueryString();
|
const query = parseConfigQueryString();
|
||||||
|
|
||||||
|
const conf = s.clashAPIConfigs[s.selectedClashAPIConfigIndex];
|
||||||
|
const url = new URL(conf.baseURL);
|
||||||
if (query.hostname) {
|
if (query.hostname) {
|
||||||
s.clashAPIConfig.hostname = query.hostname;
|
url.hostname = query.hostname;
|
||||||
}
|
}
|
||||||
if (query.port) {
|
if (query.port) {
|
||||||
s.clashAPIConfig.port = query.port;
|
url.port = query.port;
|
||||||
}
|
}
|
||||||
|
// url.href is a stringifier and it appends a trailing slash
|
||||||
|
// that is not we want
|
||||||
|
conf.baseURL = trimTrailingSlash(url.href);
|
||||||
|
|
||||||
if (query.secret) {
|
if (query.secret) {
|
||||||
s.clashAPIConfig.secret = query.secret;
|
conf.secret = query.secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.theme) {
|
if (query.theme) {
|
||||||
if (query.theme === 'dark' || query.theme === 'light') {
|
if (query.theme === 'dark' || query.theme === 'light') {
|
||||||
s.theme = query.theme;
|
s.theme = query.theme;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { atom } from 'recoil';
|
import { atom } from 'recoil';
|
||||||
|
import { ClashAPIConfig } from 'src/types';
|
||||||
|
|
||||||
import * as connAPI from '../api/connections';
|
import * as connAPI from '../api/connections';
|
||||||
import * as proxiesAPI from '../api/proxies';
|
import * as proxiesAPI from '../api/proxies';
|
||||||
import { getAutoCloseOldConns,getLatencyTestUrl } from './app';
|
import { getAutoCloseOldConns, getLatencyTestUrl } from './app';
|
||||||
|
|
||||||
type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess';
|
type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess';
|
||||||
|
|
||||||
|
@ -87,13 +88,7 @@ export const getDangleProxyNames = (s: GlobalState) =>
|
||||||
export const getShowModalClosePrevConns = (s: GlobalState) =>
|
export const getShowModalClosePrevConns = (s: GlobalState) =>
|
||||||
s.proxies.showModalClosePrevConns;
|
s.proxies.showModalClosePrevConns;
|
||||||
|
|
||||||
type APIConfig = {
|
export function fetchProxies(apiConfig: ClashAPIConfig) {
|
||||||
hostname: string;
|
|
||||||
port: string;
|
|
||||||
secret?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function fetchProxies(apiConfig: APIConfig) {
|
|
||||||
return async (dispatch: any, getState: any) => {
|
return async (dispatch: any, getState: any) => {
|
||||||
const [proxiesData, providersData] = await Promise.all([
|
const [proxiesData, providersData] = await Promise.all([
|
||||||
proxiesAPI.fetchProxies(apiConfig),
|
proxiesAPI.fetchProxies(apiConfig),
|
||||||
|
@ -135,7 +130,7 @@ export function fetchProxies(apiConfig: APIConfig) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProviderByName(apiConfig: APIConfig, name: string) {
|
export function updateProviderByName(apiConfig: ClashAPIConfig, name: string) {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
await proxiesAPI.updateProviderByName(apiConfig, name);
|
await proxiesAPI.updateProviderByName(apiConfig, name);
|
||||||
|
@ -166,7 +161,7 @@ export function healthcheckProviderByName(apiConfig, name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function closeGroupConns(
|
async function closeGroupConns(
|
||||||
apiConfig: APIConfig,
|
apiConfig: ClashAPIConfig,
|
||||||
groupName: string,
|
groupName: string,
|
||||||
exceptionItemName: string
|
exceptionItemName: string
|
||||||
) {
|
) {
|
||||||
|
@ -213,7 +208,7 @@ function resolveChain(
|
||||||
async function switchProxyImpl(
|
async function switchProxyImpl(
|
||||||
dispatch: any,
|
dispatch: any,
|
||||||
getState: () => GlobalState,
|
getState: () => GlobalState,
|
||||||
apiConfig: APIConfig,
|
apiConfig: ClashAPIConfig,
|
||||||
groupName: string,
|
groupName: string,
|
||||||
itemName: string
|
itemName: string
|
||||||
) {
|
) {
|
||||||
|
@ -256,7 +251,7 @@ function closeModalClosePrevConns() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function closePrevConns(
|
function closePrevConns(
|
||||||
apiConfig: APIConfig,
|
apiConfig: ClashAPIConfig,
|
||||||
proxies: ProxiesMapping,
|
proxies: ProxiesMapping,
|
||||||
switchTo: SwitchProxyCtxItem
|
switchTo: SwitchProxyCtxItem
|
||||||
) {
|
) {
|
||||||
|
@ -267,7 +262,7 @@ function closePrevConns(
|
||||||
closeGroupConns(apiConfig, switchTo.groupName, chain[0]);
|
closeGroupConns(apiConfig, switchTo.groupName, chain[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function closePrevConnsAndTheModal(apiConfig: APIConfig) {
|
function closePrevConnsAndTheModal(apiConfig: ClashAPIConfig) {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const s = getState();
|
const s = getState();
|
||||||
const switchTo = s.proxies.switchProxyCtx?.to;
|
const switchTo = s.proxies.switchProxyCtx?.to;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export type ClashAPIConfig = {
|
export type ClashAPIConfig = {
|
||||||
hostname: string;
|
baseURL: string;
|
||||||
port: number;
|
|
||||||
secret?: string;
|
secret?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,8 @@ const postcssPlugins = () =>
|
||||||
isDev ? false : require('cssnano')(),
|
isDev ? false : require('cssnano')(),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
|
const postcssOptions = { plugins: postcssPlugins() };
|
||||||
|
|
||||||
const cssExtractPlugin = new MiniCssExtractPlugin({
|
const cssExtractPlugin = new MiniCssExtractPlugin({
|
||||||
filename: isDev ? '[name].css' : '[name].[contenthash].css',
|
filename: isDev ? '[name].css' : '[name].[contenthash].css',
|
||||||
});
|
});
|
||||||
|
@ -89,7 +91,7 @@ module.exports = {
|
||||||
children: false,
|
children: false,
|
||||||
},
|
},
|
||||||
// https://webpack.js.org/configuration/devtool/
|
// https://webpack.js.org/configuration/devtool/
|
||||||
devtool: isDev ? 'eval-source-map' : false,
|
devtool: isDev ? 'eval-source-map' : 'source-map',
|
||||||
entry: {
|
entry: {
|
||||||
// app: ['react-hot-loader/patch', './src/app.js']
|
// app: ['react-hot-loader/patch', './src/app.js']
|
||||||
app: ['./src/app.js'],
|
app: ['./src/app.js'],
|
||||||
|
@ -124,7 +126,7 @@ module.exports = {
|
||||||
use: [
|
use: [
|
||||||
isDev ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader,
|
isDev ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader,
|
||||||
{ loader: 'css-loader' },
|
{ loader: 'css-loader' },
|
||||||
{ loader: 'postcss-loader', options: { plugins: postcssPlugins } },
|
{ loader: 'postcss-loader', options: { postcssOptions } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -141,10 +143,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ loader: 'postcss-loader', options: { postcssOptions } },
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: { plugins: postcssPlugins },
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
241
yarn.lock
241
yarn.lock
|
@ -26,12 +26,12 @@
|
||||||
semver "^5.5.0"
|
semver "^5.5.0"
|
||||||
|
|
||||||
"@babel/core@^7.11.1":
|
"@babel/core@^7.11.1":
|
||||||
version "7.11.5"
|
version "7.11.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.5.tgz#6ad96e2f71899ea3f9b651f0a911e85205d1ff6d"
|
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651"
|
||||||
integrity sha512-fsEANVOcZHzrsV6dMVWqpSeXClq3lNbYrfFGme6DE25FQWe7pyeYpXyx9guqUnpy466JLzZ8z4uwSr2iv60V5Q==
|
integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.10.4"
|
"@babel/code-frame" "^7.10.4"
|
||||||
"@babel/generator" "^7.11.5"
|
"@babel/generator" "^7.11.6"
|
||||||
"@babel/helper-module-transforms" "^7.11.0"
|
"@babel/helper-module-transforms" "^7.11.0"
|
||||||
"@babel/helpers" "^7.10.4"
|
"@babel/helpers" "^7.10.4"
|
||||||
"@babel/parser" "^7.11.5"
|
"@babel/parser" "^7.11.5"
|
||||||
|
@ -45,16 +45,16 @@
|
||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
resolve "^1.3.2"
|
resolve "^1.3.2"
|
||||||
semver "^5.4.1"
|
semver "^5.4.1"
|
||||||
source-map "^0.6.1"
|
source-map "^0.5.0"
|
||||||
|
|
||||||
"@babel/generator@^7.11.5":
|
"@babel/generator@^7.11.5", "@babel/generator@^7.11.6":
|
||||||
version "7.11.5"
|
version "7.11.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.5.tgz#a5582773425a468e4ba269d9a1f701fbca6a7a82"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620"
|
||||||
integrity sha512-9UqHWJ4IwRTy4l0o8gq2ef8ws8UPzvtMkVKjTLAiRmza9p9V6Z+OfuNd9fB1j5Q67F+dVJtPC2sZXI8NM9br4g==
|
integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.11.5"
|
"@babel/types" "^7.11.5"
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
source-map "^0.6.1"
|
source-map "^0.5.0"
|
||||||
|
|
||||||
"@babel/generator@^7.8.6":
|
"@babel/generator@^7.8.6":
|
||||||
version "7.9.0"
|
version "7.9.0"
|
||||||
|
@ -1469,84 +1469,61 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^4.0.1":
|
"@typescript-eslint/eslint-plugin@^4.1.0":
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz#88bde9239e29d688315718552cf80a3490491017"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.0.tgz#7d309f60815ff35e9627ad85e41928d7b7fd443f"
|
||||||
integrity sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==
|
integrity sha512-U+nRJx8XDUqJxYF0FCXbpmD9nWt/xHDDG0zsw1vrVYAmEAuD/r49iowfurjSL2uTA2JsgtpsyG7mjO7PHf2dYw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/experimental-utils" "4.0.1"
|
"@typescript-eslint/experimental-utils" "4.1.0"
|
||||||
"@typescript-eslint/scope-manager" "4.0.1"
|
"@typescript-eslint/scope-manager" "4.1.0"
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
functional-red-black-tree "^1.0.1"
|
functional-red-black-tree "^1.0.1"
|
||||||
regexpp "^3.0.0"
|
regexpp "^3.0.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
tsutils "^3.17.1"
|
tsutils "^3.17.1"
|
||||||
|
|
||||||
"@typescript-eslint/experimental-utils@4.0.1":
|
"@typescript-eslint/experimental-utils@4.1.0", "@typescript-eslint/experimental-utils@^4.0.1":
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz#7d9a3ab6821ad5274dad2186c1aa0d93afd696eb"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.0.tgz#263d7225645c09a411c8735eeffd417f50f49026"
|
||||||
integrity sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==
|
integrity sha512-paEYLA37iqRIDPeQwAmoYSiZ3PiHsaAc3igFeBTeqRHgPnHjHLJ9OGdmP6nwAkF65p2QzEsEBtpjNUBWByNWzA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/json-schema" "^7.0.3"
|
"@types/json-schema" "^7.0.3"
|
||||||
"@typescript-eslint/scope-manager" "4.0.1"
|
"@typescript-eslint/scope-manager" "4.1.0"
|
||||||
"@typescript-eslint/types" "4.0.1"
|
"@typescript-eslint/types" "4.1.0"
|
||||||
"@typescript-eslint/typescript-estree" "4.0.1"
|
"@typescript-eslint/typescript-estree" "4.1.0"
|
||||||
eslint-scope "^5.0.0"
|
eslint-scope "^5.0.0"
|
||||||
eslint-utils "^2.0.0"
|
eslint-utils "^2.0.0"
|
||||||
|
|
||||||
"@typescript-eslint/experimental-utils@^2.5.0":
|
"@typescript-eslint/parser@^4.1.0":
|
||||||
version "2.34.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.1.0.tgz#9b0409411725f14cd7faa81a664e5051225961db"
|
||||||
integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==
|
integrity sha512-hM/WNCQTzDHgS0Ke3cR9zPndL3OTKr9OoN9CL3UqulsAjYDrglSwIIgswSmHBcSbOzLmgaMARwrQEbIumIglvQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/json-schema" "^7.0.3"
|
"@typescript-eslint/scope-manager" "4.1.0"
|
||||||
"@typescript-eslint/typescript-estree" "2.34.0"
|
"@typescript-eslint/types" "4.1.0"
|
||||||
eslint-scope "^5.0.0"
|
"@typescript-eslint/typescript-estree" "4.1.0"
|
||||||
eslint-utils "^2.0.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/parser@^4.0.1":
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.0.1.tgz#73772080db7a7a4534a35d719e006f503e664dc3"
|
|
||||||
integrity sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/scope-manager" "4.0.1"
|
|
||||||
"@typescript-eslint/types" "4.0.1"
|
|
||||||
"@typescript-eslint/typescript-estree" "4.0.1"
|
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@4.0.1":
|
"@typescript-eslint/scope-manager@4.1.0":
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz#24d93c3000bdfcc5a157dc4d32b742405a8631b5"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.0.tgz#9e389745ee9cfe12252ed1e9958808abd6b3a683"
|
||||||
integrity sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==
|
integrity sha512-HD1/u8vFNnxwiHqlWKC/Pigdn0Mvxi84Y6GzbZ5f5sbLrFKu0al02573Er+D63Sw67IffVUXR0uR8rpdfdk+vA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "4.0.1"
|
"@typescript-eslint/types" "4.1.0"
|
||||||
"@typescript-eslint/visitor-keys" "4.0.1"
|
"@typescript-eslint/visitor-keys" "4.1.0"
|
||||||
|
|
||||||
"@typescript-eslint/types@4.0.1":
|
"@typescript-eslint/types@4.1.0":
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.1.tgz#1cf72582f764931f085cb8230ff215980fe467b2"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.0.tgz#edbd3fec346f34e13ce7aa176b03b497a32c496a"
|
||||||
integrity sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==
|
integrity sha512-rkBqWsO7m01XckP9R2YHVN8mySOKKY2cophGM8K5uDK89ArCgahItQYdbg/3n8xMxzu2elss+an1TphlUpDuJw==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@2.34.0":
|
"@typescript-eslint/typescript-estree@4.1.0":
|
||||||
version "2.34.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.0.tgz#394046ead25164494218c0e3d6b960695ea967f6"
|
||||||
integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==
|
integrity sha512-r6et57qqKAWU173nWyw31x7OfgmKfMEcjJl9vlJEzS+kf9uKNRr4AVTRXfTCwebr7bdiVEkfRY5xGnpPaNPe4Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.1.1"
|
"@typescript-eslint/types" "4.1.0"
|
||||||
eslint-visitor-keys "^1.1.0"
|
"@typescript-eslint/visitor-keys" "4.1.0"
|
||||||
glob "^7.1.6"
|
|
||||||
is-glob "^4.0.1"
|
|
||||||
lodash "^4.17.15"
|
|
||||||
semver "^7.3.2"
|
|
||||||
tsutils "^3.17.1"
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@4.0.1":
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz#29a43c7060641ec51c902d9f50ac7c5866ec479f"
|
|
||||||
integrity sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "4.0.1"
|
|
||||||
"@typescript-eslint/visitor-keys" "4.0.1"
|
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
globby "^11.0.1"
|
globby "^11.0.1"
|
||||||
is-glob "^4.0.1"
|
is-glob "^4.0.1"
|
||||||
|
@ -1554,12 +1531,12 @@
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
tsutils "^3.17.1"
|
tsutils "^3.17.1"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@4.0.1":
|
"@typescript-eslint/visitor-keys@4.1.0":
|
||||||
version "4.0.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz#d4e8de62775f2a6db71c7e8539633680039fdd6c"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.0.tgz#b2d528c9484e7eda1aa4f86ccf0432fb16e4d545"
|
||||||
integrity sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==
|
integrity sha512-+taO0IZGCtCEsuNTTF2Q/5o8+fHrlml8i9YsZt2AiDCdYEJzYlsmRY991l/6f3jNXFyAWepdQj7n8Na6URiDRQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "4.0.1"
|
"@typescript-eslint/types" "4.1.0"
|
||||||
eslint-visitor-keys "^2.0.0"
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.9.0":
|
"@webassemblyjs/ast@1.9.0":
|
||||||
|
@ -3012,10 +2989,10 @@ css-declaration-sorter@^4.0.1:
|
||||||
postcss "^7.0.1"
|
postcss "^7.0.1"
|
||||||
timsort "^0.3.0"
|
timsort "^0.3.0"
|
||||||
|
|
||||||
css-loader@^4.2.2:
|
css-loader@^4.3.0:
|
||||||
version "4.2.2"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.2.2.tgz#b668b3488d566dc22ebcf9425c5f254a05808c89"
|
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e"
|
||||||
integrity sha512-omVGsTkZPVwVRpckeUnLshPp12KsmMSLqYxs12+RzM9jRR5Y+Idn/tBffjXRvOE+qW7if24cuceFJqYR5FmGBg==
|
integrity sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase "^6.0.0"
|
camelcase "^6.0.0"
|
||||||
cssesc "^3.0.0"
|
cssesc "^3.0.0"
|
||||||
|
@ -3027,7 +3004,7 @@ css-loader@^4.2.2:
|
||||||
postcss-modules-scope "^2.2.0"
|
postcss-modules-scope "^2.2.0"
|
||||||
postcss-modules-values "^3.0.0"
|
postcss-modules-values "^3.0.0"
|
||||||
postcss-value-parser "^4.1.0"
|
postcss-value-parser "^4.1.0"
|
||||||
schema-utils "^2.7.0"
|
schema-utils "^2.7.1"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
css-select-base-adapter@^0.1.1:
|
css-select-base-adapter@^0.1.1:
|
||||||
|
@ -3715,12 +3692,12 @@ eslint-plugin-import@^2.22.0:
|
||||||
resolve "^1.17.0"
|
resolve "^1.17.0"
|
||||||
tsconfig-paths "^3.9.0"
|
tsconfig-paths "^3.9.0"
|
||||||
|
|
||||||
eslint-plugin-jest@^23.20.0:
|
eslint-plugin-jest@^24.0.0:
|
||||||
version "23.20.0"
|
version "24.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz#e1d69c75f639e99d836642453c4e75ed22da4099"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.0.0.tgz#6b1c460c529104c7d16d889e76fe708b281c4d14"
|
||||||
integrity sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw==
|
integrity sha512-a0G7hSDbuBCW4PNT6MVpAyfnGbUDOqxzOyhR6wT2BIBnR7MhvfAqd6KKfsTjX+Z3gxzIHiEsihzdClU4cSc6qQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/experimental-utils" "^2.5.0"
|
"@typescript-eslint/experimental-utils" "^4.0.1"
|
||||||
|
|
||||||
eslint-plugin-jsx-a11y@^6.3.1:
|
eslint-plugin-jsx-a11y@^6.3.1:
|
||||||
version "6.3.1"
|
version "6.3.1"
|
||||||
|
@ -4295,20 +4272,20 @@ fragment-cache@^0.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
map-cache "^0.2.2"
|
map-cache "^0.2.2"
|
||||||
|
|
||||||
framer-motion@^2.6.5:
|
framer-motion@^2.6.7:
|
||||||
version "2.6.6"
|
version "2.6.7"
|
||||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.6.6.tgz#49b52c58cfab708f9e743393c714806980b0030f"
|
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.6.7.tgz#f01685750573ab24fec8b53ac48a05e8fec6deef"
|
||||||
integrity sha512-uSglqXNmJJ2YD0lq3x3ZLM7mwgwVNwoo6B3CAjeil4GJFDcENEwKNdGVMB53TbsFZwPiBLlcm9gJPQV1f9144w==
|
integrity sha512-szwqKCH/yvMtaFmtphP3np/1/5HMDbPWfmAbVMXDvofC3qDi4+XsxVnI60egCnmYGxPeE5t4JFbZjAqOZy4HPg==
|
||||||
dependencies:
|
dependencies:
|
||||||
framesync "^4.0.4"
|
framesync "^4.1.0"
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
popmotion "9.0.0-rc.12"
|
popmotion "9.0.0-rc.13"
|
||||||
style-value-types "^3.1.9"
|
style-value-types "^3.1.9"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@emotion/is-prop-valid" "^0.8.2"
|
"@emotion/is-prop-valid" "^0.8.2"
|
||||||
|
|
||||||
framesync@^4.0.4, framesync@^4.1.0:
|
framesync@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a"
|
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a"
|
||||||
integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ==
|
integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ==
|
||||||
|
@ -4452,7 +4429,7 @@ glob@^7.0.3:
|
||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
||||||
version "7.1.6"
|
version "7.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||||
|
@ -4792,15 +4769,15 @@ human-signals@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
||||||
|
|
||||||
husky@^4.0.0:
|
husky@^4.3.0:
|
||||||
version "4.2.5"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36"
|
resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.0.tgz#0b2ec1d66424e9219d359e26a51c58ec5278f0de"
|
||||||
integrity sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ==
|
integrity sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
ci-info "^2.0.0"
|
ci-info "^2.0.0"
|
||||||
compare-versions "^3.6.0"
|
compare-versions "^3.6.0"
|
||||||
cosmiconfig "^6.0.0"
|
cosmiconfig "^7.0.0"
|
||||||
find-versions "^3.2.0"
|
find-versions "^3.2.0"
|
||||||
opencollective-postinstall "^2.0.2"
|
opencollective-postinstall "^2.0.2"
|
||||||
pkg-dir "^4.2.0"
|
pkg-dir "^4.2.0"
|
||||||
|
@ -4857,13 +4834,6 @@ immer@^7.0.8:
|
||||||
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.8.tgz#41dcbc5669a76500d017bef3ad0d03ce0a1d7c1e"
|
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.8.tgz#41dcbc5669a76500d017bef3ad0d03ce0a1d7c1e"
|
||||||
integrity sha512-XnpIN8PXBBaOD43U8Z17qg6RQiKQYGDGGCIbz1ixmLGwBkSWwmrmx5X7d+hTtXDM8ur7m5OdLE0PiO+y5RB3pw==
|
integrity sha512-XnpIN8PXBBaOD43U8Z17qg6RQiKQYGDGGCIbz1ixmLGwBkSWwmrmx5X7d+hTtXDM8ur7m5OdLE0PiO+y5RB3pw==
|
||||||
|
|
||||||
import-cwd@^2.0.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
|
||||||
integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=
|
|
||||||
dependencies:
|
|
||||||
import-from "^2.1.0"
|
|
||||||
|
|
||||||
import-fresh@^2.0.0:
|
import-fresh@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
|
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
|
||||||
|
@ -4880,13 +4850,6 @@ import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
|
||||||
parent-module "^1.0.0"
|
parent-module "^1.0.0"
|
||||||
resolve-from "^4.0.0"
|
resolve-from "^4.0.0"
|
||||||
|
|
||||||
import-from@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
|
|
||||||
integrity sha1-M1238qev/VOqpHHUuAId7ja387E=
|
|
||||||
dependencies:
|
|
||||||
resolve-from "^3.0.0"
|
|
||||||
|
|
||||||
import-local@^2.0.0:
|
import-local@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
|
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
|
||||||
|
@ -5404,6 +5367,11 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
|
|
||||||
|
klona@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.3.tgz#98274552c513583ad7a01456a789a2a0b4a2a538"
|
||||||
|
integrity sha512-CgPOT3ZadDpXxKcfV56lEQ9OQSZ42Mk26gnozI+uN/k39vzD8toUhRQoqsX0m9Q3eMPEfsLWmtyUpK/yqST4yg==
|
||||||
|
|
||||||
language-subtag-registry@~0.3.2:
|
language-subtag-registry@~0.3.2:
|
||||||
version "0.3.20"
|
version "0.3.20"
|
||||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz#a00a37121894f224f763268e431c55556b0c0755"
|
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz#a00a37121894f224f763268e431c55556b0c0755"
|
||||||
|
@ -5908,10 +5876,10 @@ mkdirp@~0.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "0.0.8"
|
minimist "0.0.8"
|
||||||
|
|
||||||
modern-normalize@^0.7.0:
|
modern-normalize@^1.0.0:
|
||||||
version "0.7.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-0.7.0.tgz#023a110fb00eafc65c7e01681a6e00db64c152aa"
|
resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.0.0.tgz#539d84a1e141338b01b346f3e27396d0ed17601e"
|
||||||
integrity sha512-EiotlP2YuHgasvDZcgM5OAHAo9TV5d+GG6MNPO0wSaBRqVEc0ROPq7MuRRO7lfTGtAB6B72hTCfwA8mS6FeNeg==
|
integrity sha512-1lM+BMLGuDfsdwf3rsgBSrxJwAZHFIrQ8YR61xIqdHo0uNKI9M52wNpHSrliZATJp51On6JD0AfRxd4YGSU0lw==
|
||||||
|
|
||||||
moment@^2.10.2:
|
moment@^2.10.2:
|
||||||
version "2.24.0"
|
version "2.24.0"
|
||||||
|
@ -6586,10 +6554,10 @@ please-upgrade-node@^3.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
semver-compare "^1.0.0"
|
semver-compare "^1.0.0"
|
||||||
|
|
||||||
popmotion@9.0.0-rc.12:
|
popmotion@9.0.0-rc.13:
|
||||||
version "9.0.0-rc.12"
|
version "9.0.0-rc.13"
|
||||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.12.tgz#c5db0d9bf7f314b7cc8789257f2902965ee9f0bf"
|
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.13.tgz#0280968fb0dc3bd273cc3dbd4da24b01b6cfbcce"
|
||||||
integrity sha512-wfiXZHxG9GGwgsFuw1Ssw6ZYzwxaBcm/O+7qKmeGIokUEFgpIys3YyK7BQv9O58P6gK1Ys+psTfSt9lycrItaQ==
|
integrity sha512-M8Ksx2THYrAUrptE5Ydd3jazQAMoXxqpClR/K8xK87v4UrJUTCb39kNar/ucJ4Rs7qPqPdVu+iqPKOJhpMylXQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
framesync "^4.1.0"
|
framesync "^4.1.0"
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
|
@ -6684,23 +6652,16 @@ postcss-import@^12.0.1:
|
||||||
read-cache "^1.0.0"
|
read-cache "^1.0.0"
|
||||||
resolve "^1.1.7"
|
resolve "^1.1.7"
|
||||||
|
|
||||||
postcss-load-config@^2.0.0:
|
postcss-loader@^4.0.0:
|
||||||
version "2.1.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003"
|
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.0.0.tgz#bfd04521d2a2db69cb9e8a7cee0a5ae704e751dc"
|
||||||
integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==
|
integrity sha512-LdpfM9yCVFeJzofnaFvLf3g9oMuH2mIIqOcu81n6JHxzRNBl78GHiYWUJ5gf4c7A7VZiBCeWwfVAMw/mQCAM3Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
cosmiconfig "^5.0.0"
|
cosmiconfig "^7.0.0"
|
||||||
import-cwd "^2.0.0"
|
klona "^2.0.3"
|
||||||
|
loader-utils "^2.0.0"
|
||||||
postcss-loader@^3.0.0:
|
schema-utils "^2.7.1"
|
||||||
version "3.0.0"
|
semver "^7.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d"
|
|
||||||
integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==
|
|
||||||
dependencies:
|
|
||||||
loader-utils "^1.1.0"
|
|
||||||
postcss "^7.0.0"
|
|
||||||
postcss-load-config "^2.0.0"
|
|
||||||
schema-utils "^1.0.0"
|
|
||||||
|
|
||||||
postcss-merge-longhand@^4.0.11:
|
postcss-merge-longhand@^4.0.11:
|
||||||
version "4.0.11"
|
version "4.0.11"
|
||||||
|
@ -7278,10 +7239,10 @@ react-modal@^3.11.1:
|
||||||
react-lifecycles-compat "^3.0.0"
|
react-lifecycles-compat "^3.0.0"
|
||||||
warning "^4.0.3"
|
warning "^4.0.3"
|
||||||
|
|
||||||
react-query@^2.12.1:
|
react-query@^2.15.4:
|
||||||
version "2.14.1"
|
version "2.15.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.14.1.tgz#d4a0a721c6155fc7dc682e036c284243ff48f74e"
|
resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.15.4.tgz#0447510fc30aebba5a4b99879ec4b7155d9b3f20"
|
||||||
integrity sha512-3NONArLC0SrYSOmdJMHBGkQBNFo76YjLgN38bpWXz5NIeK0qaVxjwqobfipSX3N7dsHbLGFV9jImkky0DHLfoA==
|
integrity sha512-gEF2Ebe1MtiyLKEaVEIlRMl6rwvP/RVwP+Xf68vhXDfD91IeZkkW7plRjoaHa0/NeUPM1AgTHb1Z7NtqaYDXjA==
|
||||||
|
|
||||||
react-refresh@^0.8.2:
|
react-refresh@^0.8.2:
|
||||||
version "0.8.3"
|
version "0.8.3"
|
||||||
|
@ -7754,7 +7715,7 @@ schema-utils@^1.0.0:
|
||||||
ajv-errors "^1.0.0"
|
ajv-errors "^1.0.0"
|
||||||
ajv-keywords "^3.1.0"
|
ajv-keywords "^3.1.0"
|
||||||
|
|
||||||
schema-utils@^2.6.5, schema-utils@^2.7.0, schema-utils@^2.7.1:
|
schema-utils@^2.6.5, schema-utils@^2.7.1:
|
||||||
version "2.7.1"
|
version "2.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
|
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
|
||||||
integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
|
integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
|
||||||
|
|
Loading…
Reference in a new issue