Add Redux and reducers.

Load i18n files and add dayjs.
This commit is contained in:
Paul 2021-06-18 17:57:08 +01:00
parent 0cba2b362d
commit 27eeb3acd2
25 changed files with 1506 additions and 53 deletions

View file

@ -4,10 +4,10 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
<title>REVOLT</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/entrypoints/main.tsx"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View file

@ -3,7 +3,7 @@
"scripts": {
"dev": "vite",
"build": "rimraf build && tsc && vite build",
"serve": "vite preview",
"preview": "vite preview",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"fmt": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'"
},
@ -30,14 +30,22 @@
"@styled-icons/feather": "^10.34.0",
"@types/node": "^15.12.3",
"@types/preact-i18n": "^2.3.0",
"@types/react-helmet": "^6.1.1",
"@types/styled-components": "^5.1.10",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"dayjs": "^1.10.5",
"eslint": "^7.28.0",
"eslint-config-preact": "^1.1.4",
"localforage": "^1.9.0",
"preact-i18n": "^2.4.0-preactx",
"prettier": "^2.3.1",
"react-device-detect": "^1.17.0",
"react-helmet": "^6.1.0",
"react-overlapping-panels": "1.1.2-patch.0",
"react-redux": "^7.2.4",
"redux": "^4.1.0",
"revolt.js": "4.2.0-alpha.3-patch.0",
"rimraf": "^3.0.2",
"sass": "^1.35.1",
"styled-components": "^5.3.0",

View file

@ -1,7 +1,17 @@
import { Text } from "preact-i18n";
import Context from "./context";
import dayjs from "dayjs";
import localeData from 'dayjs/plugin/localeData';
dayjs.extend(localeData)
export function App() {
return (
<>
<h1>REVOLT</h1>
</>
<Context>
<h1><Text id="general.about" /></h1>
<h3>{ dayjs.locale() }</h3>
<h2>{ dayjs.months() }</h2>
</Context>
);
}

View file

@ -1,10 +1,162 @@
import { IntlProvider } from "preact-i18n";
import { connectState } from "../redux/connector";
import definition from "../../external/lang/en.json";
import { useEffect, useState } from "preact/hooks";
import dayjs from "dayjs";
import calendar from "dayjs/plugin/calendar";
import update from "dayjs/plugin/updateLocale";
import format from "dayjs/plugin/localizedFormat";
dayjs.extend(calendar);
dayjs.extend(format);
dayjs.extend(update);
export enum Language {
ENGLISH = "en",
ARABIC = "ar",
AZERBAIJANI = "az",
CZECH = "cs",
GERMAN = "de",
SPANISH = "es",
FINNISH = "fi",
FRENCH = "fr",
HINDI = "hi",
CROATIAN = "hr",
HUNGARIAN = "hu",
INDONESIAN = "id",
LITHUANIAN = "lt",
MACEDONIAN = "mk",
DUTCH = "nl",
POLISH = "pl",
PORTUGUESE_BRAZIL = "pt_BR",
ROMANIAN = "ro",
RUSSIAN = "ru",
SERBIAN = "sr",
SWEDISH = "sv",
TURKISH = "tr",
UKRANIAN = "uk",
CHINESE_SIMPLIFIED = "zh_Hans",
OWO = "owo",
PIRATE = "pr",
BOTTOM = "bottom",
PIGLATIN = "piglatin",
HARDCORE = "hardcore"
}
export interface LanguageEntry {
display: string;
emoji: string;
i18n: string;
dayjs?: string;
rtl?: boolean;
}
export const Languages: { [key in Language]: LanguageEntry } = {
en: {
display: "English (Traditional)",
emoji: "🇬🇧",
i18n: "en",
dayjs: "en-gb"
},
ar: { display: "عربي", emoji: "🇸🇦", i18n: "ar", rtl: true },
az: { display: "Azərbaycan dili", emoji: "🇦🇿", i18n: "az" },
cs: { display: "Čeština", emoji: "🇨🇿", i18n: "cs" },
de: { display: "Deutsch", emoji: "🇩🇪", i18n: "de" },
es: { display: "Español", emoji: "🇪🇸", i18n: "es" },
fi: { display: "suomi", emoji: "🇫🇮", i18n: "fi" },
fr: { display: "Français", emoji: "🇫🇷", i18n: "fr" },
hi: { display: "हिन्दी", emoji: "🇮🇳", i18n: "hi" },
hr: { display: "Hrvatski", emoji: "🇭🇷", i18n: "hr" },
hu: { display: "magyar", emoji: "🇭🇺", i18n: "hu" },
id: { display: "bahasa Indonesia", emoji: "🇮🇩", i18n: "id" },
lt: { display: "Lietuvių", emoji: "🇱🇹", i18n: "lt" },
mk: { display: "Македонски", emoji: "🇲🇰", i18n: "mk" },
nl: { display: "Nederlands", emoji: "🇳🇱", i18n: "nl" },
pl: { display: "Polski", emoji: "🇵🇱", i18n: "pl" },
pt_BR: {
display: "Português (do Brasil)",
emoji: "🇧🇷",
i18n: "pt_BR",
dayjs: "pt-br"
},
ro: { display: "Română", emoji: "🇷🇴", i18n: "ro" },
ru: { display: "Русский", emoji: "🇷🇺", i18n: "ru" },
sr: { display: "Српски", emoji: "🇷🇸", i18n: "sr" },
sv: { display: "Svenska", emoji: "🇸🇪", i18n: "sv" },
tr: { display: "Türkçe", emoji: "🇹🇷", i18n: "tr" },
uk: { display: "Українська", emoji: "🇺🇦", i18n: "uk" },
zh_Hans: {
display: "中文 (简体)",
emoji: "🇨🇳",
i18n: "zh_Hans",
dayjs: "zh"
},
owo: { display: "OwO", emoji: "🐱", i18n: "owo", dayjs: "en-gb" },
pr: { display: "Pirate", emoji: "🏴‍☠️", i18n: "pr", dayjs: "en-gb" },
bottom: { display: "Bottom", emoji: "🥺", i18n: "bottom", dayjs: "en-gb" },
piglatin: { display: "Pig Latin", emoji: "🐖", i18n: "piglatin", dayjs: "en-gb" },
hardcore: {
display: "Hardcore Mode",
emoji: "🔥",
i18n: "hardcore",
dayjs: "en-gb"
}
};
interface Props {
children: JSX.Element | JSX.Element[];
locale: Language;
}
export default function Locale({ children }: Props) {
return <IntlProvider definition={definition}>{children}</IntlProvider>;
function Locale({ children, locale }: Props) {
const [defns, setDefinition] = useState(definition);
const lang = Languages[locale];
useEffect(() => {
if (locale === 'en') {
setDefinition(definition);
dayjs.locale('en');
return;
}
if (lang.i18n === "hardcore") {
setDefinition({} as any);
return;
}
import(
`../../external/lang/${lang.i18n}.json`
).then(async lang_file => {
let defn = lang_file.default;
let target = lang.dayjs ?? lang.i18n;
let dayjs_locale = await import(/* @vite-ignore */ `/node_modules/dayjs/esm/locale/${target}.js`);
if (defn.dayjs) {
dayjs.updateLocale(target, { calendar: defn.dayjs });
}
dayjs.locale(dayjs_locale.default);
setDefinition(defn);
});
}, [locale]);
useEffect(() => {
document.body.style.direction = lang.rtl ? "rtl" : "";
}, [ lang.rtl ]);
return <IntlProvider definition={defns}>{children}</IntlProvider>;
}
export default connectState<Omit<Props, 'locale'>>(
Locale,
state => {
return {
locale: state.locale
};
},
true
);

View file

@ -1,7 +1,78 @@
import { isTouchscreenDevice } from "../lib/isTouchscreenDevice";
import { createGlobalStyle } from "styled-components";
import { Children } from "../types/Preact";
import { Helmet } from "react-helmet";
// ! TEMP START
const a = {
export type Variables =
| "accent"
| "background"
| "foreground"
| "block"
| "message-box"
| "mention"
| "success"
| "warning"
| "error"
| "hover"
| "sidebar-active"
| "scrollbar-thumb"
| "scrollbar-track"
| "primary-background"
| "primary-header"
| "secondary-background"
| "secondary-foreground"
| "secondary-header"
| "tertiary-background"
| "tertiary-foreground"
| "status-online"
| "status-away"
| "status-busy"
| "status-streaming"
| "status-invisible";
export type Theme = {
[variable in Variables]: string;
} & {
light?: boolean;
css?: string;
};
export interface ThemeOptions {
preset?: string;
custom?: Partial<Theme>;
}
// Generated from https://gitlab.insrt.uk/revolt/community/themes
export const PRESETS: { [key: string]: Theme } = {
light: {
light: true,
accent: "#FD6671",
background: "#F6F6F6",
foreground: "#101010",
block: "#414141",
"message-box": "#F1F1F1",
mention: "rgba(251, 255, 0, 0.40)",
success: "#65E572",
warning: "#FAA352",
error: "#F06464",
hover: "rgba(0, 0, 0, 0.2)",
"sidebar-active": "#FD6671",
"scrollbar-thumb": "#CA525A",
"scrollbar-track": "transparent",
"primary-background": "#FFFFFF",
"primary-header": "#F1F1F1",
"secondary-background": "#F1F1F1",
"secondary-foreground": "#888888",
"secondary-header": "#F1F1F1",
"tertiary-background": "#4D4D4D",
"tertiary-foreground": "#646464",
"status-online": "#3ABF7E",
"status-away": "#F39F00",
"status-busy": "#F84848",
"status-streaming": "#977EFF",
"status-invisible": "#A5A5A5",
},
dark: {
light: false,
accent: "#FD6671",
background: "#191919",
@ -28,14 +99,39 @@ const a = {
"status-busy": "#F84848",
"status-streaming": "#977EFF",
"status-invisible": "#A5A5A5",
},
};
export const GlobalTheme = createGlobalStyle`
const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
:root {
${Object.keys(a).map((key) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return `--${key}: ${(a as any)[key]};`;
${(props) =>
(Object.keys(props.theme) as Variables[]).map((key) => {
return `--${key}: ${props.theme[key]};`;
})}
}
`;
// ! TEMP END
interface Props {
children: Children;
}
export default function Theme(props: Props) {
const theme = PRESETS.dark;
return (
<>
<Helmet>
<meta
name="theme-color"
content={
isTouchscreenDevice
? theme["primary-header"]
: theme["tertiary-background"]
}
/>
</Helmet>
<GlobalTheme theme={theme} />
{props.children}
</>
);
}

15
src/context/index.tsx Normal file
View file

@ -0,0 +1,15 @@
import State from "../redux/State";
import { Children } from "../types/Preact";
import Locale from "./Locale";
import Theme from "./Theme";
export default function Context({ children }: { children: Children }) {
return (
<State>
<Locale>
<Theme>{children}</Theme>
</Locale>
</State>
);
}

View file

@ -0,0 +1,19 @@
import { Client } from 'revolt.js';
export enum ClientStatus {
LOADING,
READY,
OFFLINE,
DISCONNECTED,
CONNECTING,
RECONNECTING,
ONLINE
}
export const RevoltJSClient = new Client({
autoReconnect: false,
apiURL: process.env.API_SERVER,
debug: process.env.NODE_ENV === "development",
// Match sw.js#13
// db: new Db("state", 3, ["channels", "servers", "users", "members"])
});

View file

@ -0,0 +1,10 @@
import { Message } from "revolt.js/dist/api/objects";
export type MessageObject = Omit<Message, "edited"> & { edited?: string };
export function mapMessage(message: Partial<Message>) {
const { edited, ...msg } = message;
return {
...msg,
edited: edited?.$date
} as MessageObject;
}

View file

@ -0,0 +1,7 @@
import { isDesktop, isMobile, isTablet } from "react-device-detect";
export const isTouchscreenDevice =
isDesktop && !isTablet
? false
: (typeof window !== "undefined"
? navigator.maxTouchPoints > 0
: false) || isMobile;

View file

@ -1,5 +1,5 @@
import { render } from "preact";
import "../styles/index.scss";
import "./styles/index.scss";
import { App } from "./app";
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

32
src/redux/State.tsx Normal file
View file

@ -0,0 +1,32 @@
import { store } from ".";
import localForage from "localforage";
import { Provider } from 'react-redux';
import { Children } from "../types/Preact";
import { useEffect, useState } from "preact/hooks";
async function loadState() {
const state = await localForage.getItem("state");
if (state) {
store.dispatch({ type: "__INIT", state });
}
}
interface Props {
children: Children
}
export default function State(props: Props) {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
loadState().then(() => setLoaded(true));
}, []);
if (!loaded) return null;
return (
<Provider store={store}>
{ props.children }
</Provider>
)
}

16
src/redux/connector.tsx Normal file
View file

@ -0,0 +1,16 @@
import { State } from ".";
import { h } from "preact";
//import { memo } from "preact/compat";
import { connect, ConnectedComponent } from "react-redux";
export function connectState<T>(
component: (props: any) => h.JSX.Element | null,
mapKeys: (state: State, props: T) => any,
useDispatcher?: boolean
): ConnectedComponent<(props: any) => h.JSX.Element | null, T> {
return (
useDispatcher
? connect(mapKeys, dispatcher => { return { dispatcher } })
: connect(mapKeys)
)(component);//(memo(component));
}

62
src/redux/index.ts Normal file
View file

@ -0,0 +1,62 @@
import { createStore } from "redux";
import rootReducer from "./reducers";
import localForage from "localforage";
import { Typing } from "./reducers/typing";
import { Drafts } from "./reducers/drafts";
import { AuthState } from "./reducers/auth";
import { Language } from "../context/Locale";
import { Unreads } from "./reducers/unreads";
import { SyncOptions } from "./reducers/sync";
import { Settings } from "./reducers/settings";
import { QueuedMessage } from "./reducers/queue";
import { ExperimentOptions } from "./reducers/experiments";
export type State = {
locale: Language;
auth: AuthState;
settings: Settings;
unreads: Unreads;
queue: QueuedMessage[];
typing: Typing;
drafts: Drafts;
sync: SyncOptions;
experiments: ExperimentOptions;
};
export const store = createStore((state: any, action: any) => {
if (process.env.NODE_ENV === "development") {
console.debug("State Update:", action);
}
if (action.type === "__INIT") {
return action.state;
}
return rootReducer(state, action);
});
// Save state using localForage.
store.subscribe(() => {
const {
locale,
auth,
settings,
unreads,
queue,
drafts,
sync,
experiments
} = store.getState() as State;
localForage.setItem("state", {
locale,
auth,
settings,
unreads,
queue,
drafts,
sync,
experiments
});
});

View file

@ -0,0 +1,48 @@
import { Auth } from "revolt.js/dist/api/objects";
export interface AuthState {
accounts: {
[key: string]: {
session: Auth.Session;
};
};
active?: string;
}
export type AuthAction =
| { type: undefined }
| {
type: "LOGIN";
session: Auth.Session;
}
| {
type: "LOGOUT";
user_id?: string;
};
export function auth(
state = { accounts: {} } as AuthState,
action: AuthAction
): AuthState {
switch (action.type) {
case "LOGIN":
return {
accounts: {
...state.accounts,
[action.session.user_id]: {
session: action.session
}
},
active: action.session.user_id
};
case "LOGOUT":
const accounts = Object.assign({}, state.accounts);
action.user_id && delete accounts[action.user_id];
return {
accounts
};
default:
return state;
}
}

View file

@ -0,0 +1,33 @@
export type Drafts = { [key: string]: string };
export type DraftAction =
| { type: undefined }
| {
type: "SET_DRAFT";
channel: string;
content: string;
}
| {
type: "CLEAR_DRAFT";
channel: string;
}
| {
type: "RESET";
};
export function drafts(state: Drafts = {}, action: DraftAction): Drafts {
switch (action.type) {
case "SET_DRAFT":
return {
...state,
[action.channel]: action.content
};
case "CLEAR_DRAFT":
const { [action.channel]: _, ...newState } = state;
return newState;
case "RESET":
return {};
default:
return state;
}
}

View file

@ -0,0 +1,43 @@
export type Experiments = never;
export const AVAILABLE_EXPERIMENTS: Experiments[] = [ ];
export interface ExperimentOptions {
enabled?: Experiments[]
}
export type ExperimentsAction =
| { type: undefined }
| {
type: "EXPERIMENTS_ENABLE";
key: Experiments;
}
| {
type: "EXPERIMENTS_DISABLE";
key: Experiments;
};
export function experiments(
state = {} as ExperimentOptions,
action: ExperimentsAction
): ExperimentOptions {
switch (action.type) {
case "EXPERIMENTS_ENABLE":
return {
...state,
enabled: [
...(state.enabled ?? [])
.filter(x => AVAILABLE_EXPERIMENTS.includes(x))
.filter(v => v !== action.key),
action.key
]
};
case "EXPERIMENTS_DISABLE":
return {
...state,
enabled: state.enabled?.filter(v => v !== action.key)
.filter(x => AVAILABLE_EXPERIMENTS.includes(x))
};
default:
return state;
}
}

View file

@ -0,0 +1,47 @@
import { combineReducers } from "redux";
import { settings, SettingsAction } from "./settings";
import { locale, LocaleAction } from "./locale";
import { auth, AuthAction } from "./auth";
import { unreads, UnreadsAction } from "./unreads";
import { queue, QueueAction } from "./queue";
import { typing, TypingAction } from "./typing";
import { drafts, DraftAction } from "./drafts";
import { sync, SyncAction } from "./sync";
import { experiments, ExperimentsAction } from "./experiments";
export default combineReducers({
locale,
auth,
settings,
unreads,
queue,
typing,
drafts,
sync,
experiments
});
export type Action =
| LocaleAction
| AuthAction
| SettingsAction
| UnreadsAction
| QueueAction
| TypingAction
| DraftAction
| SyncAction
| ExperimentsAction
| { type: "__INIT"; state: any };
export type WithDispatcher = { dispatcher: (action: Action) => void };
export function filter(obj: any, keys: string[]) {
const newObj: any = {};
for (const key of keys) {
const v = obj[key];
if (v) newObj[key] = v;
}
return newObj;
}

View file

@ -0,0 +1,50 @@
import { Language } from "../../context/Locale";
import { SyncData, SyncKeys, SyncUpdateAction } from "./sync";
export type LocaleAction =
| { type: undefined }
| {
type: "SET_LOCALE";
locale: Language;
}
| SyncUpdateAction;
export function findLanguage(lang?: string): Language {
if (!lang) {
if (typeof navigator === "undefined") {
lang = Language.ENGLISH;
} else {
lang = navigator.language;
}
}
const code = lang.replace("-", "_");
const short = code.split("_")[0];
for (const key of Object.keys(Language)) {
const value = (Language as any)[key];
if (value.startsWith(code)) {
return value;
}
}
for (const key of Object.keys(Language).reverse()) {
const value = (Language as any)[key];
if (value.startsWith(short)) {
return value;
}
}
return Language.ENGLISH;
}
export function locale(state = findLanguage(), action: LocaleAction): Language {
switch (action.type) {
case "SET_LOCALE":
return action.locale;
case "SYNC_UPDATE":
return (action.update.locale?.[1] ?? state) as Language;
default:
return state;
}
}

103
src/redux/reducers/queue.ts Normal file
View file

@ -0,0 +1,103 @@
import { MessageObject } from "../../context/revoltjs/messages";
export enum QueueStatus {
SENDING = "sending",
ERRORED = "errored"
}
export interface QueuedMessage {
id: string;
channel: string;
data: MessageObject;
status: QueueStatus;
error?: string;
}
export type QueueAction =
| { type: undefined }
| {
type: "QUEUE_ADD";
nonce: string;
channel: string;
message: MessageObject;
}
| {
type: "QUEUE_FAIL";
nonce: string;
error: string;
}
| {
type: "QUEUE_START";
nonce: string;
}
| {
type: "QUEUE_REMOVE";
nonce: string;
}
| {
type: "QUEUE_DROP_ALL";
}
| {
type: "QUEUE_FAIL_ALL";
}
| {
type: "RESET";
};
export function queue(
state: QueuedMessage[] = [],
action: QueueAction
): QueuedMessage[] {
switch (action.type) {
case "QUEUE_ADD": {
return [
...state.filter(x => x.id !== action.nonce),
{
id: action.nonce,
data: action.message,
channel: action.channel,
status: QueueStatus.SENDING
}
];
}
case "QUEUE_FAIL": {
const entry = state.find(
x => x.id === action.nonce
) as QueuedMessage;
return [
...state.filter(x => x.id !== action.nonce),
{
...entry,
status: QueueStatus.ERRORED,
error: action.error
}
];
}
case "QUEUE_START": {
const entry = state.find(
x => x.id === action.nonce
) as QueuedMessage;
return [
...state.filter(x => x.id !== action.nonce),
{
...entry,
status: QueueStatus.SENDING
}
];
}
case "QUEUE_REMOVE":
return state.filter(x => x.id !== action.nonce);
case "QUEUE_FAIL_ALL":
return state.map(x => {
return {
...x,
status: QueueStatus.ERRORED
};
});
case "QUEUE_DROP_ALL":
case "RESET":
return [];
default:
return state;
}
}

View file

@ -0,0 +1,98 @@
import { filter } from ".";
import { SyncUpdateAction } from "./sync";
import { Theme, ThemeOptions } from "../../context/Theme";
export interface NotificationOptions {
desktopEnabled?: boolean;
soundEnabled?: boolean;
outgoingSoundEnabled?: boolean;
}
export type EmojiPacks = 'mutant' | 'twemoji' | 'noto' | 'openmoji';
export interface AppearanceOptions {
emojiPack?: EmojiPacks
}
export interface Settings {
theme?: ThemeOptions;
appearance?: AppearanceOptions;
notification?: NotificationOptions;
}
export type SettingsAction =
| { type: undefined }
| {
type: "SETTINGS_SET_THEME";
theme: ThemeOptions;
}
| {
type: "SETTINGS_SET_THEME_OVERRIDE";
custom?: Partial<Theme>;
}
| {
type: "SETTINGS_SET_NOTIFICATION_OPTIONS";
options: NotificationOptions;
}
| {
type: "SETTINGS_SET_APPEARANCE";
options: Partial<AppearanceOptions>;
}
| SyncUpdateAction
| {
type: "RESET";
};
export function settings(
state = {} as Settings,
action: SettingsAction
): Settings {
// setEmojiPack(state.appearance?.emojiPack ?? 'mutant');
switch (action.type) {
case "SETTINGS_SET_THEME":
return {
...state,
theme: {
...filter(state.theme, [ 'custom', 'preset' ]),
...action.theme,
}
};
case "SETTINGS_SET_THEME_OVERRIDE":
return {
...state,
theme: {
...state.theme,
custom: {
...state.theme?.custom,
...action.custom
}
}
};
case "SETTINGS_SET_NOTIFICATION_OPTIONS":
return {
...state,
notification: {
...state.notification,
...action.options
}
};
case "SETTINGS_SET_APPEARANCE":
return {
...state,
appearance: {
...filter(state.appearance, [ 'emojiPack' ]),
...action.options
}
}
case "SYNC_UPDATE":
return {
...state,
appearance: action.update.appearance?.[1] ?? state.appearance,
theme: action.update.theme?.[1] ?? state.theme
}
case "RESET":
return {};
default:
return state;
}
}

View file

@ -0,0 +1,85 @@
import { AppearanceOptions } from "./settings";
import { Language } from "../../context/Locale";
import { ThemeOptions } from "../../context/Theme";
export type SyncKeys = 'theme' | 'appearance' | 'locale';
export interface SyncData {
locale?: Language;
theme?: ThemeOptions;
appearance?: AppearanceOptions;
}
export const DEFAULT_ENABLED_SYNC: SyncKeys[] = [ 'theme', 'appearance', 'locale' ];
export interface SyncOptions {
disabled?: SyncKeys[]
revision?: {
[key: string]: number
}
}
export type SyncUpdateAction = {
type: "SYNC_UPDATE";
update: { [key in SyncKeys]?: [ number, SyncData[key] ] }
};
export type SyncAction =
| { type: undefined }
| {
type: "SYNC_ENABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_DISABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_SET_REVISION";
key: SyncKeys;
timestamp: number;
}
| SyncUpdateAction;
export function sync(
state = {} as SyncOptions,
action: SyncAction
): SyncOptions {
switch (action.type) {
case "SYNC_DISABLE_KEY":
return {
...state,
disabled: [
...(state.disabled ?? []).filter(v => v !== action.key),
action.key
]
};
case "SYNC_ENABLE_KEY":
return {
...state,
disabled: state.disabled?.filter(v => v !== action.key)
};
case "SYNC_SET_REVISION":
return {
...state,
revision: {
...state.revision,
[action.key]: action.timestamp
}
};
case "SYNC_UPDATE":
const revision = { ...state.revision };
for (const key of Object.keys(action.update)) {
const value = action.update[key as SyncKeys];
if (value) {
revision[key] = value[0];
}
}
return {
...state,
revision
}
default:
return state;
}
}

View file

@ -0,0 +1,46 @@
export type TypingUser = { id: string, started: number };
export type Typing = { [key: string]: TypingUser[] };
export type TypingAction =
| { type: undefined }
| {
type: "TYPING_START";
channel: string;
user: string;
}
| {
type: "TYPING_STOP";
channel: string;
user: string;
}
| {
type: "RESET";
};
export function typing(state: Typing = {}, action: TypingAction): Typing {
switch (action.type) {
case "TYPING_START":
return {
...state,
[action.channel]: [
...(state[action.channel] ?? []).filter(
x => x.id !== action.user
),
{
id: action.user,
started: + new Date()
}
]
};
case "TYPING_STOP":
return {
...state,
[action.channel]:
state[action.channel]?.filter(x => x.id !== action.user) ?? []
};
case "RESET":
return {};
default:
return state;
}
}

View file

@ -0,0 +1,68 @@
import { Sync } from "revolt.js/dist/api/objects";
export interface Unreads {
[key: string]: Partial<Omit<Sync.ChannelUnread, '_id'>>;
}
export type UnreadsAction =
| { type: undefined }
| {
type: "UNREADS_MARK_READ";
channel: string;
message: string;
request: boolean;
}
| {
type: "UNREADS_SET";
unreads: Sync.ChannelUnread[];
}
| {
type: "UNREADS_MENTION";
channel: string;
message: string;
}
| {
type: "RESET";
};
export function unreads(state = {}, action: UnreadsAction): Unreads {
switch (action.type) {
case "UNREADS_MARK_READ":
if (action.request) {
// client.req('PUT', `/channels/${action.channel}/ack/${action.message}` as '/channels/id/ack/id');
}
return {
...state,
[action.channel]: {
last_id: action.message
}
};
case "UNREADS_SET":
{
const obj: Unreads = {};
for (const entry of action.unreads) {
const { _id, ...v } = entry;
obj[_id.channel] = v;
}
return obj;
}
case "UNREADS_MENTION":
{
const obj = (state as any)[action.channel];
return {
...state,
[action.channel]: {
...obj,
mentions: [ ...(obj?.mentions ?? []), action.message ]
}
}
}
case "RESET":
return {};
default:
return state;
}
}

View file

@ -3,7 +3,7 @@ import styled from 'styled-components';
import '../src/styles/index.scss'
import { render } from 'preact'
import { GlobalTheme } from '../src/context/Theme';
import Theme from '../src/context/Theme';
export const UIDemo = styled.div`
gap: 12px;
@ -61,8 +61,9 @@ export function UI() {
}
render(<>
<GlobalTheme />
<Theme>
<UIDemo>
<UI />
</UIDemo>
</Theme>
</>, document.getElementById('app')!)

414
yarn.lock
View file

@ -183,7 +183,7 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2"
integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==
"@babel/runtime@^7.10.5", "@babel/runtime@^7.14.0":
"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.1", "@babel/runtime@^7.14.0", "@babel/runtime@^7.9.2":
version "7.14.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
@ -264,6 +264,26 @@
resolved "https://registry.yarnpkg.com/@fontsource/open-sans/-/open-sans-4.4.5.tgz#07b31617e62ed753c94cabcf552ebaed4de497ce"
integrity sha512-PDWEvO1/p8OAHHiielvEmwGXHNbZhrZn96ojV7+/mKgFu+cCUcGVJl9sFs97rCWLe3hKQsYLEsJs4EiLjwa+UQ==
"@insertish/mutable@1.0.6":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@insertish/mutable/-/mutable-1.0.6.tgz#f42eaba8528ff68cc8065d51f9bbbd30a24f34de"
integrity sha512-FTaPbesmBwcr3iKfbA2udFto61/sL7rOiCM08vBbE2X0wC63nsvTos6gnkwa1Nwom1v15jjrc/4B0YqI3vbZ/Q==
dependencies:
"@insertish/zangodb" "^1.0.12"
eventemitter3 "^4.0.7"
lodash.isequal "^4.5.0"
"@insertish/zangodb@1.0.12", "@insertish/zangodb@^1.0.12":
version "1.0.12"
resolved "https://registry.yarnpkg.com/@insertish/zangodb/-/zangodb-1.0.12.tgz#25264ec065720fa43c7549ec7245e4f3839cb0ea"
integrity sha512-JlLI12Xqt1xvv/p2/AHs163ZYMZsB3sJyjB8yaAs6QcG0tyRBTIyxV5ISEAkAPo5kzlFza5z5oH82yQe/qw5RQ==
dependencies:
clone "^2.1.2"
deepmerge "^4.2.2"
memoizee "^0.4.15"
object-hash "^2.1.1"
q "^1.5.1"
"@mdn/browser-compat-data@^2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-2.0.7.tgz#72ec37b9c1e00ce0b4e0309d753be18e2da12ee3"
@ -360,7 +380,7 @@
"@babel/runtime" "^7.10.5"
"@emotion/is-prop-valid" "^0.8.7"
"@types/hoist-non-react-statics@*":
"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
@ -390,6 +410,23 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-helmet@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.1.tgz#4fde22cbcaa1b461642e1d719cc6162d95acb110"
integrity sha512-VmSCMz6jp/06DABoY60vQa++h1YFt0PfAI23llxBJHbowqFgLUL0dhS1AQeVPNqYfRp9LAfokrfWACTNeobOrg==
dependencies:
"@types/react" "*"
"@types/react-redux@^7.1.16":
version "7.1.16"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21"
integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*":
version "17.0.11"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.11.tgz#67fcd0ddbf5a0b083a0f94e926c7d63f3b836451"
@ -611,6 +648,13 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
axios@^0.19.2:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
dependencies:
follow-redirects "1.5.10"
babel-eslint@^10.0.1:
version "10.1.0"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@ -739,6 +783,11 @@ chalk@^4.0.0:
optionalDependencies:
fsevents "~2.3.2"
clone@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -785,7 +834,7 @@ core-js@^3.6.5:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.14.0.tgz#62322b98c71cc2018b027971a69419e2425c2a6c"
integrity sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA==
cross-spawn@^7.0.2:
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -813,6 +862,26 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
d@1, d@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
dependencies:
es5-ext "^0.10.50"
type "^1.0.1"
dayjs@^1.10.5:
version "1.10.5"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
@ -825,6 +894,11 @@ deep-is@^0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@ -858,6 +932,11 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
duplexer@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
electron-to-chromium@^1.3.723:
version "1.3.752"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz#0728587f1b9b970ec9ffad932496429aef750d09"
@ -906,6 +985,42 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
version "0.10.53"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
dependencies:
es6-iterator "~2.0.3"
es6-symbol "~3.1.3"
next-tick "~1.0.0"
es6-iterator@^2.0.3, es6-iterator@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
dependencies:
d "1"
es5-ext "^0.10.35"
es6-symbol "^3.1.1"
es6-symbol@^3.1.1, es6-symbol@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
dependencies:
d "^1.0.1"
ext "^1.1.2"
es6-weak-map@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53"
integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==
dependencies:
d "1"
es5-ext "^0.10.46"
es6-iterator "^2.0.3"
es6-symbol "^3.1.1"
esbuild@^0.12.5:
version "0.12.9"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.9.tgz#bed4e7087c286cd81d975631f77d47feb1660070"
@ -1106,6 +1221,44 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
dependencies:
d "1"
es5-ext "~0.10.14"
event-stream@=3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=
dependencies:
duplexer "~0.1.1"
from "~0"
map-stream "~0.1.0"
pause-stream "0.0.11"
split "0.3"
stream-combiner "~0.0.4"
through "~2.3.1"
eventemitter3@^4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
exponential-backoff@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.0.tgz#9409c7e579131f8bd4b32d7d8094a911040f2e68"
integrity sha512-oBuz5SYz5zzyuHINoe9ooePwSu0xApKWgeNzok4hZ5YKXFh9zrQBEM15CXqoZkJJPuI2ArvqjPQd8UKJA753XA==
ext@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
dependencies:
type "^2.0.0"
extend@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@ -1180,6 +1333,18 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"
from@~0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -1284,7 +1449,7 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0:
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -1301,6 +1466,11 @@ ignore@^5.1.4:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@ -1404,6 +1574,11 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-promise@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-regex@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f"
@ -1429,6 +1604,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
isomorphic-ws@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -1490,6 +1670,20 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
lie@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=
dependencies:
immediate "~3.0.5"
localforage@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1"
integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g==
dependencies:
lie "3.1.1"
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@ -1502,6 +1696,16 @@ lodash.clonedeep@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.defaultsdeep@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.memoize@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -1536,6 +1740,32 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
lru-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=
dependencies:
es5-ext "~0.10.2"
map-stream@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=
memoizee@^0.4.15:
version "0.4.15"
resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72"
integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==
dependencies:
d "^1.0.1"
es5-ext "^0.10.53"
es6-weak-map "^2.0.3"
event-emitter "^0.3.5"
is-promise "^2.2.2"
lru-queue "^0.1.0"
next-tick "^1.1.0"
timers-ext "^0.1.7"
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
@ -1561,6 +1791,11 @@ minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@ -1576,6 +1811,21 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
next-tick@1, next-tick@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
next-tick@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
node-cleanup@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c"
integrity sha1-esGavSl+Caf3KnFUXZUbUX5N3iw=
node-releases@^1.1.71:
version "1.1.73"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20"
@ -1591,6 +1841,11 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-hash@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
object-inspect@^1.10.3, object-inspect@^1.9.0:
version "1.10.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
@ -1709,6 +1964,13 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
pause-stream@0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=
dependencies:
through "~2.3"
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
@ -1770,17 +2032,51 @@ prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
ps-tree@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd"
integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==
dependencies:
event-stream "=3.3.4"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
q@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
react-is@^16.7.0, react-is@^16.8.1:
react-device-detect@^1.17.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.17.0.tgz#a00b4fd6880cebfab3fd8a42a79dc0290cdddca9"
integrity sha512-bBblIStwpHmoS281JFIVqeimcN3LhpoP5YKDWzxQdBIUP8S2xPvHDgizLDhUq2ScguLfVPmwfF5y268EEQR60w==
dependencies:
ua-parser-js "^0.7.24"
react-fast-compare@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-helmet@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
dependencies:
object-assign "^4.1.1"
prop-types "^15.7.2"
react-fast-compare "^3.1.1"
react-side-effect "^2.1.0"
react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -1790,6 +2086,23 @@ react-overlapping-panels@1.1.2-patch.0:
resolved "https://registry.yarnpkg.com/react-overlapping-panels/-/react-overlapping-panels-1.1.2-patch.0.tgz#335649735c029d334daea19ef6e30efc76b128fd"
integrity sha512-PaXxk5HxBMYg46iADGGhkgXqqweJWo7yjSeT4/o0Q3s6Q7pl7Rz23lM3oW2gdJHBDOs/zBpZ+ZIP4j6grQlCOA==
react-redux@^7.2.4:
version "7.2.4"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.13.1"
react-side-effect@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3"
integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@ -1797,6 +2110,13 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
redux@^4.0.0, redux@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==
dependencies:
"@babel/runtime" "^7.9.2"
regenerator-runtime@^0.13.4:
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
@ -1846,6 +2166,22 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
revolt.js@4.2.0-alpha.3-patch.0:
version "4.2.0-alpha.3-patch.0"
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.2.0-alpha.3-patch.0.tgz#ca79731c2b2fa9a8dbfbc5c9f84bef6ee2759918"
integrity sha512-g4eXHDbQyjKEiDOjj+3BxbRwPuVfOCYsnVqOiOXoAib4k48c27N+ZU0apYV25/AzCvIoYGDtVfY3I33UkTl1Rw==
dependencies:
"@insertish/mutable" "1.0.6"
"@insertish/zangodb" "1.0.12"
axios "^0.19.2"
eventemitter3 "^4.0.7"
exponential-backoff "^3.1.0"
isomorphic-ws "^4.0.1"
lodash.defaultsdeep "^4.6.1"
tsc-watch "^4.1.0"
ulid "^2.3.0"
ws "^7.2.1"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -1946,11 +2282,30 @@ source-map@^0.5.0:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
split@0.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=
dependencies:
through "2"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
stream-combiner@~0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=
dependencies:
duplexer "~0.1.1"
string-argv@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.1.2.tgz#c5b7bc03fb2b11983ba3a72333dd0559e77e4738"
integrity sha512-mBqPGEOMNJKXRo7z0keX0wlAhbBAjilUdPW13nN0PecVryZxdHIeM7TqbsSUA7VYuS00HGC6mojP7DlQzfa9ZA==
string-width@^4.2.0:
version "4.2.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
@ -2049,6 +2404,19 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
through@2, through@~2.3, through@~2.3.1:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timers-ext@^0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6"
integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==
dependencies:
es5-ext "~0.10.46"
next-tick "1"
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@ -2061,6 +2429,17 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
tsc-watch@^4.1.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/tsc-watch/-/tsc-watch-4.4.0.tgz#3ebbf1db54bcef6bfe534b330fa87284a4139320"
integrity sha512-+0Yey6ptOOXAnt44OKTk2/EnQnmA0auL7VWXm9d9abMS4tabt0Xdr9B4AK6OJbWAre9ZdLA81+Nk8sz9unptyA==
dependencies:
cross-spawn "^7.0.3"
node-cleanup "^2.1.2"
ps-tree "^1.2.0"
string-argv "^0.1.1"
strip-ansi "^6.0.0"
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@ -2085,11 +2464,31 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
type@^2.0.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d"
integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
typescript@^4.3.2:
version "4.3.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.3.tgz#5401db69bd3203daf1851a1a74d199cb3112c11a"
integrity sha512-rUvLW0WtF7PF2b9yenwWUi9Da9euvDRhmH7BLyBG4DCFfOJ850LGNknmRpp8Z8kXNUPObdZQEfKOiHtXuQHHKA==
ua-parser-js@^0.7.24:
version "0.7.28"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
ulid@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f"
integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==
unbox-primitive@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
@ -2152,6 +2551,11 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^7.2.1:
version "7.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691"
integrity sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"