diff --git a/package.json b/package.json index 26f85870..0b20ee71 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@preact/preset-vite": "^2.0.0", "@styled-icons/bootstrap": "^10.34.0", "@styled-icons/feather": "^10.34.0", - "@types/node": "^15.12.3", + "@types/node": "^15.12.4", "@types/preact-i18n": "^2.3.0", "@types/react-helmet": "^6.1.1", "@types/react-router-dom": "^5.1.7", @@ -40,6 +40,7 @@ "detect-browser": "^5.2.0", "eslint": "^7.28.0", "eslint-config-preact": "^1.1.4", + "idb": "^6.1.2", "localforage": "^1.9.0", "preact-i18n": "^2.4.0-preactx", "prettier": "^2.3.1", @@ -50,7 +51,7 @@ "react-redux": "^7.2.4", "react-router-dom": "^5.2.0", "redux": "^4.1.0", - "revolt.js": "4.2.0-alpha.3-patch.0", + "revolt.js": "4.3.0", "rimraf": "^3.0.2", "sass": "^1.35.1", "styled-components": "^5.3.0", diff --git a/src/app.tsx b/src/app.tsx index 605c43e0..28e68f59 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -4,6 +4,22 @@ import Context from "./context"; import { Login } from "./pages/login/Login"; +import { useForceUpdate, useSelf, useUser } from "./context/revoltjs/hooks"; + +function Test() { + const ctx = useForceUpdate(); + + let self = useSelf(ctx); + let bree = useUser('01EZZJ98RM1YVB1FW9FG221CAN', ctx); + + return ( +
+

logged in as { self?.username }

+

bree: { JSON.stringify(bree) }

+
+ ) +} + export function App() { return ( @@ -15,7 +31,7 @@ export function App() { -

revolt app

+
diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx index a6067306..dc919f20 100644 --- a/src/context/revoltjs/RevoltClient.tsx +++ b/src/context/revoltjs/RevoltClient.tsx @@ -1,14 +1,19 @@ +import { openDB } from 'idb'; import { Client } from "revolt.js"; +import { takeError } from "./error"; import { createContext } from "preact"; -import { useState } from "preact/hooks"; import { Children } from "../../types/Preact"; import { Route } from "revolt.js/dist/api/routes"; +import { useEffect, useState } from "preact/hooks"; import { connectState } from "../../redux/connector"; +import Preloader from "../../components/ui/Preloader"; import { WithDispatcher } from "../../redux/reducers"; import { AuthState } from "../../redux/reducers/auth"; import { SyncOptions } from "../../redux/reducers/sync"; +import { registerEvents, setReconnectDisallowed } from "./events"; export enum ClientStatus { + INIT, LOADING, READY, OFFLINE, @@ -26,19 +31,13 @@ export interface ClientOperations { } export interface AppState { + client: Client; status: ClientStatus; operations: ClientOperations; } export const AppContext = createContext(undefined as any); -export const RevoltClient = new Client({ - autoReconnect: false, - apiURL: import.meta.env.VITE_API_URL, - debug: process.env.NODE_ENV === "development", - // db: new Db("state", 3, ["channels", "servers", "users", "members"]) -}); - type Props = WithDispatcher & { auth: AuthState; sync: SyncOptions; @@ -46,18 +45,176 @@ type Props = WithDispatcher & { }; function Context({ auth, sync, children, dispatcher }: Props) { - const [status, setStatus] = useState(ClientStatus.LOADING); + const [status, setStatus] = useState(ClientStatus.INIT); + const [client, setClient] = useState(undefined as unknown as Client); + + useEffect(() => { + (async () => { + let db; + try { + db = await openDB('state', 3, { + upgrade(db) { + for (let store of [ "channels", "servers", "users", "members" ]) { + db.createObjectStore(store, { + keyPath: '_id' + }); + } + }, + }); + } catch (err) { + console.error('Failed to open IndexedDB store, continuing without.'); + } + + setClient(new Client({ + autoReconnect: false, + apiURL: import.meta.env.VITE_API_URL, + debug: import.meta.env.DEV, + db + })); + + setStatus(ClientStatus.LOADING); + })(); + }, [ ]); + + if (status === ClientStatus.INIT) return null; const value: AppState = { + client, status, operations: { - login: async data => {}, - logout: async shouldRequest => {}, - loggedIn: () => false, - ready: () => false + login: async data => { + setReconnectDisallowed(true); + + try { + const onboarding = await client.login(data); + setReconnectDisallowed(false); + const login = () => + dispatcher({ + type: "LOGIN", + session: client.session as any + }); + + if (onboarding) { + /*openScreen({ + id: "onboarding", + callback: async (username: string) => { + await (onboarding as any)(username, true); + login(); + } + });*/ + } else { + login(); + } + } catch (err) { + setReconnectDisallowed(false); + throw err; + } + }, + logout: async shouldRequest => { + dispatcher({ type: "LOGOUT" }); + + delete client.user; + dispatcher({ type: "RESET" }); + + // openScreen({ id: "none" }); + setStatus(ClientStatus.READY); + + client.websocket.disconnect(); + + if (shouldRequest) { + try { + await client.logout(); + } catch (err) { + console.error(err); + } + } + }, + loggedIn: () => typeof auth.active !== "undefined", + ready: () => ( + value.operations.loggedIn() && + typeof client.user !== "undefined" + ) } }; + useEffect( + () => registerEvents({ ...value, dispatcher }, setStatus, client), + [ client ] + ); + + useEffect(() => { + (async () => { + await client.restore(); + + if (auth.active) { + dispatcher({ type: "QUEUE_FAIL_ALL" }); + + const active = auth.accounts[auth.active]; + client.user = client.users.get(active.session.user_id); + if (!navigator.onLine) { + return setStatus(ClientStatus.OFFLINE); + } + + if (value.operations.ready()) + setStatus(ClientStatus.CONNECTING); + + if (navigator.onLine) { + await client + .fetchConfiguration() + .catch(() => + console.error("Failed to connect to API server.") + ); + } + + try { + await client.fetchConfiguration(); + const callback = await client.useExistingSession( + active.session + ); + + //if (callback) { + /*openScreen({ id: "onboarding", callback });*/ + //} else { + /* + // ! FIXME: all this code needs to be re-written + (async () => { + // ! FIXME: should be included in Ready payload + props.dispatcher({ + type: 'SYNC_UPDATE', + // ! FIXME: write a procedure to resolve merge conflicts + update: mapSync( + await client.syncFetchSettings(DEFAULT_ENABLED_SYNC.filter(x => !props.sync?.disabled?.includes(x))) + ) + }); + })() + + props.dispatcher({ type: 'UNREADS_SET', unreads: await client.syncFetchUnreads() });*/ + //} + } catch (err) { + setStatus(ClientStatus.DISCONNECTED); + const error = takeError(err); + if (error === "Forbidden") { + value.operations.logout(true); + // openScreen({ id: "signed_out" }); + } else { + // openScreen({ id: "error", error }); + } + } + } else { + await client + .fetchConfiguration() + .catch(() => + console.error("Failed to connect to API server.") + ); + setStatus(ClientStatus.READY); + } + })(); + }, []); + + if (status === ClientStatus.LOADING) { + return ; + } + return ( { children } diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts new file mode 100644 index 00000000..0a10c538 --- /dev/null +++ b/src/context/revoltjs/events.ts @@ -0,0 +1,121 @@ +import { ClientboundNotification } from "revolt.js/dist/websocket/notifications"; +import { WithDispatcher } from "../../redux/reducers"; +import { Client, Message } from "revolt.js/dist"; +import { + AppState, + ClientStatus +} from "./RevoltClient"; +import { StateUpdater } from "preact/hooks"; + +export var preventReconnect = false; +let preventUntil = 0; + +export function setReconnectDisallowed(allowed: boolean) { + preventReconnect = allowed; +} + +export function registerEvents({ + operations, + dispatcher +}: AppState & WithDispatcher, setStatus: StateUpdater, client: Client) { + const listeners = { + connecting: () => + operations.ready() && setStatus(ClientStatus.CONNECTING), + + dropped: () => { + operations.ready() && setStatus(ClientStatus.DISCONNECTED); + + if (preventReconnect) return; + function reconnect() { + preventUntil = +new Date() + 2000; + client.websocket.connect().catch(err => console.error(err)); + } + + if (+new Date() > preventUntil) { + setTimeout(reconnect, 2000); + } else { + reconnect(); + } + }, + + packet: (packet: ClientboundNotification) => { + switch (packet.type) { + case "ChannelStartTyping": { + if (packet.user === client.user?._id) return; + dispatcher({ + type: "TYPING_START", + channel: packet.id, + user: packet.user + }); + break; + } + case "ChannelStopTyping": { + if (packet.user === client.user?._id) return; + dispatcher({ + type: "TYPING_STOP", + channel: packet.id, + user: packet.user + }); + break; + } + case "ChannelAck": { + dispatcher({ + type: "UNREADS_MARK_READ", + channel: packet.id, + message: packet.message_id, + request: false + }); + break; + } + } + }, + + message: (message: Message) => { + if (message.mentions?.includes(client.user!._id)) { + dispatcher({ + type: "UNREADS_MENTION", + channel: message.channel, + message: message._id + }); + } + }, + + ready: () => { + setStatus(ClientStatus.ONLINE); + } + }; + + let listenerFunc: { [key: string]: Function }; + if (import.meta.env.DEV) { + listenerFunc = {}; + for (const listener of Object.keys(listeners)) { + listenerFunc[listener] = (...args: any[]) => { + console.debug(`Calling ${listener} with`, args); + (listeners as any)[listener](...args); + }; + } + } else { + listenerFunc = listeners; + } + + for (const listener of Object.keys(listenerFunc)) { + client.addListener(listener, (listenerFunc as any)[listener]); + } + + /*const online = () => + operations.ready() && setStatus(ClientStatus.RECONNECTING); + const offline = () => + operations.ready() && setStatus(ClientStatus.OFFLINE); + + window.addEventListener("online", online); + window.addEventListener("offline", offline); + + return () => { + for (const listener of Object.keys(listenerFunc)) { + RevoltClient.removeListener(listener, (listenerFunc as any)[listener]); + } + + window.removeEventListener("online", online); + window.removeEventListener("offline", offline); + };*/ +} diff --git a/src/context/revoltjs/hooks.ts b/src/context/revoltjs/hooks.ts new file mode 100644 index 00000000..3f100b03 --- /dev/null +++ b/src/context/revoltjs/hooks.ts @@ -0,0 +1,108 @@ +import { useCallback, useContext, useEffect, useState } from "preact/hooks"; +import { Channels, Servers, Users } from "revolt.js/dist/api/objects"; +import { Client, PermissionCalculator } from 'revolt.js'; +import { AppContext } from "./RevoltClient"; + +interface HookContext { + client: Client, + forceUpdate: () => void +} + +export function useForceUpdate(context?: HookContext): HookContext { + const { client } = useContext(AppContext); + if (context) return context; + const [, updateState] = useState({}); + return { client, forceUpdate: useCallback(() => updateState({}), []) }; +} + +function useObject(type: string, id?: string | string[], context?: HookContext) { + const ctx = useForceUpdate(context); + + function mutation(target: string) { + if (typeof id === 'string' ? target === id : + Array.isArray(id) ? id.includes(target) : true) { + ctx.forceUpdate(); + } + } + + const map = (ctx.client as any)[type]; + useEffect(() => { + map.addListener("update", mutation); + return () => map.removeListener("update", mutation); + }, [id]); + + return typeof id === 'string' ? map.get(id) + : Array.isArray(id) ? id.map(x => map.get(x)) + : map.toArray(); +} + +export function useUser(id?: string, context?: HookContext) { + if (typeof id === "undefined") return; + return useObject('users', id, context) as Readonly | undefined; +} + +export function useSelf(context?: HookContext) { + const ctx = useForceUpdate(context); + return useUser(ctx.client.user!._id, ctx); +} + +export function useUsers(ids?: string[], context?: HookContext) { + return useObject('users', ids, context) as (Readonly | undefined)[]; +} + +export function useChannel(id?: string, context?: HookContext) { + if (typeof id === "undefined") return; + return useObject('channels', id, context) as Readonly | undefined; +} + +export function useChannels(ids?: string[], context?: HookContext) { + return useObject('channels', ids, context) as (Readonly | undefined)[]; +} + +export function useServer(id?: string, context?: HookContext) { + if (typeof id === "undefined") return; + return useObject('servers', id, context) as Readonly | undefined; +} + +export function useServers(ids?: string[], context?: HookContext) { + return useObject('servers', ids, context) as (Readonly | undefined)[]; +} + +export function useUserPermission(id: string, context?: HookContext) { + const ctx = useForceUpdate(context); + + const mutation = (target: string) => (target === id) && ctx.forceUpdate(); + useEffect(() => { + ctx.client.users.addListener("update", mutation); + return () => ctx.client.users.removeListener("update", mutation); + }, [id]); + + let calculator = new PermissionCalculator(ctx.client); + return calculator.forUser(id); +} + +export function useChannelPermission(id: string, context?: HookContext) { + const ctx = useForceUpdate(context); + + const mutation = (target: string) => (target === id) && ctx.forceUpdate(); + useEffect(() => { + ctx.client.channels.addListener("update", mutation); + return () => ctx.client.channels.removeListener("update", mutation); + }, [id]); + + let calculator = new PermissionCalculator(ctx.client); + return calculator.forChannel(id); +} + +export function useServerPermission(id: string, context?: HookContext) { + const ctx = useForceUpdate(context); + + const mutation = (target: string) => (target === id) && ctx.forceUpdate(); + useEffect(() => { + ctx.client.servers.addListener("update", mutation); + return () => ctx.client.servers.removeListener("update", mutation); + }, [id]); + + let calculator = new PermissionCalculator(ctx.client); + return calculator.forServer(id); +} diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx index 6e463dd0..3eda13ca 100644 --- a/src/pages/login/Login.tsx +++ b/src/pages/login/Login.tsx @@ -6,7 +6,7 @@ import { APP_VERSION } from "../../version"; import { LIBRARY_VERSION } from "revolt.js"; import { Route, Switch } from "react-router-dom"; import { ThemeContext } from "../../context/Theme"; -import { RevoltClient } from "../../context/revoltjs/RevoltClient"; +import { AppContext } from "../../context/revoltjs/RevoltClient"; import background from "./background.jpg"; @@ -17,6 +17,7 @@ import { FormReset, FormSendReset } from "./forms/FormReset"; export const Login = () => { const theme = useContext(ThemeContext); + const { client } = useContext(AppContext); return (
@@ -27,7 +28,7 @@ export const Login = () => {
API:{" "} - {RevoltClient.configuration?.revolt ?? "???"}{" "} + {client.configuration?.revolt ?? "???"}{" "} · revolt.js: {LIBRARY_VERSION}{" "} · App: {APP_VERSION} diff --git a/src/pages/login/forms/CaptchaBlock.tsx b/src/pages/login/forms/CaptchaBlock.tsx index 7030dbd5..0ba486a2 100644 --- a/src/pages/login/forms/CaptchaBlock.tsx +++ b/src/pages/login/forms/CaptchaBlock.tsx @@ -1,9 +1,9 @@ import { Text } from "preact-i18n"; -import { useEffect } from "preact/hooks"; import styles from "../Login.module.scss"; import HCaptcha from "@hcaptcha/react-hcaptcha"; +import { useContext, useEffect } from "preact/hooks"; import Preloader from "../../../components/ui/Preloader"; -import { RevoltClient } from "../../../context/revoltjs/RevoltClient"; +import { AppContext } from "../../../context/revoltjs/RevoltClient"; export interface CaptchaProps { onSuccess: (token?: string) => void; @@ -11,19 +11,21 @@ export interface CaptchaProps { } export function CaptchaBlock(props: CaptchaProps) { + const { client } = useContext(AppContext); + useEffect(() => { - if (!RevoltClient.configuration?.features.captcha.enabled) { + if (!client.configuration?.features.captcha.enabled) { props.onSuccess(); } }, []); - if (!RevoltClient.configuration?.features.captcha.enabled) + if (!client.configuration?.features.captcha.enabled) return ; return (
props.onSuccess(token)} />
diff --git a/src/pages/login/forms/Form.tsx b/src/pages/login/forms/Form.tsx index ff28139c..56cdfadf 100644 --- a/src/pages/login/forms/Form.tsx +++ b/src/pages/login/forms/Form.tsx @@ -1,14 +1,14 @@ import { Legal } from "./Legal"; import { Text } from "preact-i18n"; import { Link } from "react-router-dom"; -import { useState } from "preact/hooks"; import styles from "../Login.module.scss"; import { useForm } from "react-hook-form"; import { MailProvider } from "./MailProvider"; +import { useContext, useState } from "preact/hooks"; import { CheckCircle, Mail } from "@styled-icons/feather"; import { CaptchaBlock, CaptchaProps } from "./CaptchaBlock"; import { takeError } from "../../../context/revoltjs/error"; -import { RevoltClient } from "../../../context/revoltjs/RevoltClient"; +import { AppContext } from "../../../context/revoltjs/RevoltClient"; import FormField from "../FormField"; import Button from "../../../components/ui/Button"; @@ -34,6 +34,8 @@ function getInviteCode() { } export function Form({ page, callback }: Props) { + const { client } = useContext(AppContext); + const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(undefined); const [error, setGlobalError] = useState(undefined); @@ -73,7 +75,7 @@ export function Form({ page, callback }: Props) { try { if ( - RevoltClient.configuration?.features.captcha.enabled && + client.configuration?.features.captcha.enabled && page !== "reset" ) { setCaptcha({ @@ -103,7 +105,7 @@ export function Form({ page, callback }: Props) { if (typeof success !== "undefined") { return (
- {RevoltClient.configuration?.features.email ? ( + {client.configuration?.features.email ? ( <>

@@ -157,7 +159,7 @@ export function Form({ page, callback }: Props) { error={errors.password?.message} /> )} - {RevoltClient.configuration?.features.invite_only && + {client.configuration?.features.invite_only && page === "create" && ( { - await RevoltClient.register(process.env.API_SERVER as string, data); + await client.register(import.meta.env.VITE_API_URL, data); }} /> ); diff --git a/src/pages/login/forms/FormResend.tsx b/src/pages/login/forms/FormResend.tsx index badbabf3..9d52b20f 100644 --- a/src/pages/login/forms/FormResend.tsx +++ b/src/pages/login/forms/FormResend.tsx @@ -1,12 +1,15 @@ -import { RevoltClient } from "../../../context/revoltjs/RevoltClient"; +import { AppContext } from "../../../context/revoltjs/RevoltClient"; +import { useContext } from "preact/hooks"; import { Form } from "./Form"; export function FormResend() { + const { client } = useContext(AppContext); + return (
{ - await RevoltClient.req("POST", "/auth/resend", data); + await client.req("POST", "/auth/resend", data); }} /> ); diff --git a/src/pages/login/forms/FormReset.tsx b/src/pages/login/forms/FormReset.tsx index 01ddee76..7d8ecdb4 100644 --- a/src/pages/login/forms/FormReset.tsx +++ b/src/pages/login/forms/FormReset.tsx @@ -1,13 +1,16 @@ import { Form } from "./Form"; +import { useContext } from "preact/hooks"; import { useHistory, useParams } from "react-router-dom"; -import { RevoltClient } from "../../../context/revoltjs/RevoltClient"; +import { AppContext } from "../../../context/revoltjs/RevoltClient"; export function FormSendReset() { + const { client } = useContext(AppContext); + return ( { - await RevoltClient.req("POST", "/auth/send_reset", data); + await client.req("POST", "/auth/send_reset", data); }} /> ); @@ -15,13 +18,14 @@ export function FormSendReset() { export function FormReset() { const { token } = useParams<{ token: string }>(); + const { client } = useContext(AppContext); const history = useHistory(); return ( { - await RevoltClient.req("POST", "/auth/reset" as any, { + await client.req("POST", "/auth/reset" as any, { token, ...(data as any) }); diff --git a/src/redux/index.ts b/src/redux/index.ts index a8e2270f..6099d9e7 100644 --- a/src/redux/index.ts +++ b/src/redux/index.ts @@ -28,7 +28,7 @@ export type State = { // eslint-disable-next-line @typescript-eslint/no-explicit-any export const store = createStore((state: any, action: any) => { - if (process.env.NODE_ENV === "development") { + if (import.meta.env.DEV) { console.debug("State Update:", action); } diff --git a/yarn.lock b/yarn.lock index 5f17267e..dd31e17e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -960,26 +960,14 @@ resolved "https://registry.yarnpkg.com/@hcaptcha/react-hcaptcha/-/react-hcaptcha-0.3.6.tgz#cbbb9abdaea451a4df408bc9d476e8b17f0b63f4" integrity sha512-DQ5nvGVbbhd2IednxRhCV9wiPcCmclEV7bH98yGynGCXzO5XftO/XC0a1M1kEf9Ee+CLO/u+1HM/uE/PSrC3vQ== -"@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== +"@insertish/mutable@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@insertish/mutable/-/mutable-1.1.0.tgz#06f95f855691ccb69ee3c339887a80bcd1498116" + integrity sha512-NH7aCGFAKRE1gFprrW/HsJoWCWQy18TZBarxLdeLVWdLFvkb2lD6Z5B70oOoUHFNpykiTC8IcRonsd9Xn13n8Q== 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" @@ -1144,11 +1132,16 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== -"@types/node@*", "@types/node@^15.12.3": +"@types/node@*": version "15.12.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.3.tgz#2817bf5f25bc82f56579018c53f7d41b1830b1af" integrity sha512-SNt65CPCXvGNDZ3bvk1TQ0Qxoe3y1RKH88+wZ2Uf05dduBCqqFQ76ADP9pbT+Cpvj60SkRppMCh2Zo8tDixqjQ== +"@types/node@^15.12.4": + version "15.12.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.4.tgz#e1cf817d70a1e118e81922c4ff6683ce9d422e26" + integrity sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA== + "@types/preact-i18n@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@types/preact-i18n/-/preact-i18n-2.3.0.tgz#d99d4a9ad03b0b65e57ed4d874447de74384e32f" @@ -1604,11 +1597,6 @@ 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" @@ -1706,14 +1694,6 @@ 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" @@ -1846,42 +1826,6 @@ 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" @@ -2087,14 +2031,6 @@ 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" @@ -2118,13 +2054,6 @@ exponential-backoff@^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" @@ -2354,6 +2283,11 @@ hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react- dependencies: react-is "^16.7.0" +idb@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/idb/-/idb-6.1.2.tgz#82ef5c951b8e1f47875d36ccafa4bedafc62f2f1" + integrity sha512-1DNDVu3yDhAZkFDlJf0t7r+GLZ248F5pTAtA7V0oVG3yjmV125qZOx3g0XpAEkGZVYQiFDAsSOnGet2bhugc3w== + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -2482,11 +2416,6 @@ is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= -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" @@ -2696,13 +2625,6 @@ 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" - magic-string@^0.25.0, magic-string@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" @@ -2715,20 +2637,6 @@ map-stream@~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" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -2787,16 +2695,6 @@ 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" @@ -2817,11 +2715,6 @@ 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" @@ -3032,11 +2925,6 @@ punycode@^2.1.0: 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" @@ -3243,13 +3131,12 @@ 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== +revolt.js@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.0.tgz#dc396470da82dd58eac74150ed9e3d64f67c28db" + integrity sha512-QFD0KQMk6e6bOioZJSSSnzgtx76yJLFSp9LyM1fIIelP02vrMpU1wO7s89lE+7jljh7SVgJqyCfZmlshdyb7Ew== dependencies: - "@insertish/mutable" "1.0.6" - "@insertish/zangodb" "1.0.12" + "@insertish/mutable" "1.1.0" axios "^0.19.2" eventemitter3 "^4.0.7" exponential-backoff "^3.1.0" @@ -3586,14 +3473,6 @@ through@2, through@~2.3, through@~2.3.1: 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" - tiny-invariant@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" @@ -3663,16 +3542,6 @@ 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"