diff --git a/src/context/intermediate/popovers/UserProfile.tsx b/src/context/intermediate/popovers/UserProfile.tsx
index b8c4e2d16f0b10866dd5a211647b2a58fdd9f2b9..c0d4bb4651ece7454d018b936cce7d1ea5ddaf8a 100644
--- a/src/context/intermediate/popovers/UserProfile.tsx
+++ b/src/context/intermediate/popovers/UserProfile.tsx
@@ -1,17 +1,14 @@
 import { Money } from "@styled-icons/boxicons-regular";
 import { Envelope, Edit, UserPlus, Shield } from "@styled-icons/boxicons-solid";
 import { Link, useHistory } from "react-router-dom";
-import { Users } from "revolt.js/dist/api/objects";
+import { Profile, RelationshipStatus } from "revolt-api/types/Users";
 import { UserPermission } from "revolt.js/dist/api/permissions";
 import { Route } from "revolt.js/dist/api/routes";
-import { decodeTime } from "ulid";
 
 import styles from "./UserProfile.module.scss";
 import { Localizer, Text } from "preact-i18n";
 import { useContext, useEffect, useLayoutEffect, useState } from "preact/hooks";
 
-import { useData } from "../../../mobx/State";
-
 import ChannelIcon from "../../../components/common/ChannelIcon";
 import Tooltip from "../../../components/common/Tooltip";
 import UserIcon from "../../../components/common/user/UserIcon";
@@ -27,14 +24,13 @@ import {
     StatusContext,
     useClient,
 } from "../../revoltjs/RevoltClient";
-import { useForceUpdate, useUserPermission } from "../../revoltjs/hooks";
 import { useIntermediate } from "../Intermediate";
 
 interface Props {
     user_id: string;
     dummy?: boolean;
     onClose: () => void;
-    dummyProfile?: Users.Profile;
+    dummyProfile?: Profile;
 }
 
 enum Badges {
@@ -48,7 +44,7 @@ enum Badges {
 export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
     const { openScreen, writeClipboard } = useIntermediate();
 
-    const [profile, setProfile] = useState<undefined | null | Users.Profile>(
+    const [profile, setProfile] = useState<undefined | null | Profile>(
         undefined,
     );
     const [mutual, setMutual] = useState<
@@ -60,22 +56,18 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
     const status = useContext(StatusContext);
     const [tab, setTab] = useState("profile");
 
-    const ctx = useForceUpdate();
-    const permissions = useUserPermission(client.user!._id, ctx);
-
-    const store = useData();
-    if (!store.users.has(user_id)) {
+    const user = client.users.get(user_id);
+    if (!user) {
         useEffect(onClose, []);
         return null;
     }
 
-    const user = store.users.get(user_id)!;
-    const users = mutual?.users.map((id) => store.users.get(id));
+    const users = mutual?.users.map((id) => client.users.get(id));
 
-    const mutualGroups = [...store.channels.values()].filter(
+    const mutualGroups = [...client.channels.values()].filter(
         (channel) =>
             channel?.channel_type === "Group" &&
-            channel.recipients!.includes(user_id),
+            channel.recipient_ids!.includes(user_id),
     );
 
     useLayoutEffect(() => {
@@ -94,7 +86,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
         if (dummy) return;
         if (status === ClientStatus.ONLINE && typeof mutual === "undefined") {
             setMutual(null);
-            client.users.fetchMutual(user_id).then((data) => setMutual(data));
+            user.fetchMutual().then(setMutual);
         }
     }, [mutual, status]);
 
@@ -103,10 +95,9 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
         if (status === ClientStatus.ONLINE && typeof profile === "undefined") {
             setProfile(null);
 
-            if (permissions & UserPermission.ViewProfile) {
-                client.users
-                    .fetchProfile(user_id)
-                    .then((data) => setProfile(data))
+            if (user.permission & UserPermission.ViewProfile) {
+                user.fetchProfile()
+                    .then(setProfile)
                     .catch(() => {});
             }
         }
@@ -114,10 +105,8 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
 
     const backgroundURL =
         profile &&
-        client.users.getBackgroundURL(profile, { width: 1000 }, true);
-    const badges =
-        (user.badges ?? 0) |
-        (decodeTime(user._id) < 1623751765790 ? Badges.EarlyAdopter : 0);
+        client.generateFileURL(profile.background, { width: 1000 }, true);
+    const badges = user.badges ?? 0;
 
     return (
         <Modal
@@ -150,7 +139,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
                             </span>
                         )}
                     </div>
-                    {user.relationship === Users.Relationship.Friend && (
+                    {user.relationship === RelationshipStatus.Friend && (
                         <Localizer>
                             <Tooltip
                                 content={
@@ -166,7 +155,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
                             </Tooltip>
                         </Localizer>
                     )}
-                    {user.relationship === Users.Relationship.User && (
+                    {user.relationship === RelationshipStatus.User && (
                         <IconButton
                             onClick={() => {
                                 onClose();
@@ -176,12 +165,9 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
                             <Edit size={28} />
                         </IconButton>
                     )}
-                    {(user.relationship === Users.Relationship.Incoming ||
-                        user.relationship === Users.Relationship.None) && (
-                        <IconButton
-                            onClick={() =>
-                                client.users.addFriend(user.username)
-                            }>
+                    {(user.relationship === RelationshipStatus.Incoming ||
+                        user.relationship === RelationshipStatus.None) && (
+                        <IconButton onClick={() => user.addFriend()}>
                             <UserPlus size={28} />
                         </IconButton>
                     )}
@@ -192,7 +178,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
                         onClick={() => setTab("profile")}>
                         <Text id="app.special.popovers.user_profile.profile" />
                     </div>
-                    {user.relationship !== Users.Relationship.User && (
+                    {user.relationship !== RelationshipStatus.User && (
                         <>
                             <div
                                 data-active={tab === "friends"}
diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx
index 5e08ce74c52e4f6ab4d5ad1ec1a674756ab40d91..719a3341ee00cfc2e23b6060b037b9f9ef6c843d 100644
--- a/src/context/revoltjs/Notifications.tsx
+++ b/src/context/revoltjs/Notifications.tsx
@@ -1,6 +1,8 @@
+import { autorun } from "mobx";
 import { Route, Switch, useHistory, useParams } from "react-router-dom";
-import { Message, SYSTEM_USER_ID, User } from "revolt.js";
-import { Users } from "revolt.js/dist/api/objects";
+import { Presence, RelationshipStatus } from "revolt-api/types/Users";
+import { SYSTEM_USER_ID } from "revolt.js";
+import { Message } from "revolt.js/dist/maps/Messages";
 import { decodeTime } from "ulid";
 
 import { useContext, useEffect } from "preact/hooks";
@@ -50,41 +52,36 @@ function Notifier({ options, notifs }: Props) {
     const playSound = useContext(SoundContext);
 
     async function message(msg: Message) {
-        if (msg.author === client.user!._id) return;
-        if (msg.channel === channel_id && document.hasFocus()) return;
-        if (client.user!.status?.presence === Users.Presence.Busy) return;
+        if (msg.author_id === client.user!._id) return;
+        if (msg.channel_id === channel_id && document.hasFocus()) return;
+        if (client.user!.status?.presence === Presence.Busy) return;
+        if (msg.author?.relationship === RelationshipStatus.Blocked) return;
 
-        const channel = client.channels.get(msg.channel);
-        const author = client.users.get(msg.author);
-        if (!channel) return;
-        if (author?.relationship === Users.Relationship.Blocked) return;
-
-        const notifState = getNotificationState(notifs, channel);
+        const notifState = getNotificationState(notifs, msg.channel!);
         if (!shouldNotify(notifState, msg, client.user!._id)) return;
 
         playSound("message");
         if (!showNotification) return;
 
         let title;
-        switch (channel.channel_type) {
+        switch (msg.channel?.channel_type) {
             case "SavedMessages":
                 return;
             case "DirectMessage":
-                title = `@${author?.username}`;
+                title = `@${msg.author?.username}`;
                 break;
             case "Group":
-                if (author?._id === SYSTEM_USER_ID) {
-                    title = channel.name;
+                if (msg.author?._id === SYSTEM_USER_ID) {
+                    title = msg.channel.name;
                 } else {
-                    title = `@${author?.username} - ${channel.name}`;
+                    title = `@${msg.author?.username} - ${msg.channel.name}`;
                 }
                 break;
             case "TextChannel":
-                const server = client.servers.get(channel.server);
-                title = `@${author?.username} (#${channel.name}, ${server?.name})`;
+                title = `@${msg.author?.username} (#${msg.channel.name}, ${msg.channel.server?.name})`;
                 break;
             default:
-                title = msg.channel;
+                title = msg.channel?._id;
                 break;
         }
 
@@ -103,70 +100,82 @@ function Notifier({ options, notifs }: Props) {
         let body, icon;
         if (typeof msg.content === "string") {
             body = client.markdownToText(msg.content);
-            icon = client.users.getAvatarURL(msg.author, { max_side: 256 });
+            icon = msg.author?.generateAvatarURL({ max_side: 256 });
         } else {
             const users = client.users;
             switch (msg.content.type) {
                 case "user_added":
                 case "user_remove":
-                    body = translate(
-                        `app.main.channel.system.${
-                            msg.content.type === "user_added"
-                                ? "added_by"
-                                : "removed_by"
-                        }`,
-                        {
-                            user: users.get(msg.content.id)?.username,
-                            other_user: users.get(msg.content.by)?.username,
-                        },
-                    );
-                    icon = client.users.getAvatarURL(msg.content.id, {
-                        max_side: 256,
-                    });
+                    {
+                        let user = users.get(msg.content.id);
+                        body = translate(
+                            `app.main.channel.system.${
+                                msg.content.type === "user_added"
+                                    ? "added_by"
+                                    : "removed_by"
+                            }`,
+                            {
+                                user: user?.username,
+                                other_user: users.get(msg.content.by)?.username,
+                            },
+                        );
+                        icon = user?.generateAvatarURL({
+                            max_side: 256,
+                        });
+                    }
                     break;
                 case "user_joined":
                 case "user_left":
                 case "user_kicked":
                 case "user_banned":
-                    body = translate(
-                        `app.main.channel.system.${msg.content.type}`,
-                        { user: users.get(msg.content.id)?.username },
-                    );
-                    icon = client.users.getAvatarURL(msg.content.id, {
-                        max_side: 256,
-                    });
+                    {
+                        let user = users.get(msg.content.id);
+                        body = translate(
+                            `app.main.channel.system.${msg.content.type}`,
+                            { user: user?.username },
+                        );
+                        icon = user?.generateAvatarURL({
+                            max_side: 256,
+                        });
+                    }
                     break;
                 case "channel_renamed":
-                    body = translate(
-                        `app.main.channel.system.channel_renamed`,
-                        {
-                            user: users.get(msg.content.by)?.username,
-                            name: msg.content.name,
-                        },
-                    );
-                    icon = client.users.getAvatarURL(msg.content.by, {
-                        max_side: 256,
-                    });
+                    {
+                        let user = users.get(msg.content.by);
+                        body = translate(
+                            `app.main.channel.system.channel_renamed`,
+                            {
+                                user: users.get(msg.content.by)?.username,
+                                name: msg.content.name,
+                            },
+                        );
+                        icon = user?.generateAvatarURL({
+                            max_side: 256,
+                        });
+                    }
                     break;
                 case "channel_description_changed":
                 case "channel_icon_changed":
-                    body = translate(
-                        `app.main.channel.system.${msg.content.type}`,
-                        { user: users.get(msg.content.by)?.username },
-                    );
-                    icon = client.users.getAvatarURL(msg.content.by, {
-                        max_side: 256,
-                    });
+                    {
+                        let user = users.get(msg.content.by);
+                        body = translate(
+                            `app.main.channel.system.${msg.content.type}`,
+                            { user: users.get(msg.content.by)?.username },
+                        );
+                        icon = user?.generateAvatarURL({
+                            max_side: 256,
+                        });
+                    }
                     break;
             }
         }
 
-        const notif = await createNotification(title, {
+        const notif = await createNotification(title!, {
             icon,
             image,
             body,
             timestamp: decodeTime(msg._id),
-            tag: msg.channel,
+            tag: msg.channel?._id,
             badge: "/assets/icons/android-chrome-512x512.png",
             silent: true,
         });
@@ -174,7 +183,7 @@ function Notifier({ options, notifs }: Props) {
         if (notif) {
             notif.addEventListener("click", () => {
                 window.focus();
-                const id = msg.channel;
+                const id = msg.channel_id;
                 if (id !== channel_id) {
                     const channel = client.channels.get(id);
                     if (channel) {
@@ -189,15 +198,15 @@ function Notifier({ options, notifs }: Props) {
                 }
             });
 
-            notifications[msg.channel] = notif;
+            notifications[msg.channel_id] = notif;
             notif.addEventListener(
                 "close",
-                () => delete notifications[msg.channel],
+                () => delete notifications[msg.channel_id],
             );
         }
     }
 
-    async function relationship(user: User, property: string) {
+    /*async function relationship(user: User, property: string) {
         if (client.user?.status?.presence === Users.Presence.Busy) return;
         if (property !== "relationship") return;
         if (!showNotification) return;
@@ -219,7 +228,7 @@ function Notifier({ options, notifs }: Props) {
         }
 
         const notif = await createNotification(event, {
-            icon: client.users.getAvatarURL(user._id, { max_side: 256 }),
+            icon: user.generateAvatarURL({ max_side: 256 }),
             badge: "/assets/icons/android-chrome-512x512.png",
             timestamp: +new Date(),
         });
@@ -227,15 +236,17 @@ function Notifier({ options, notifs }: Props) {
         notif?.addEventListener("click", () => {
             history.push(`/friends`);
         });
-    }
+    }*/
 
     useEffect(() => {
+        // ! FIXME: need event from client about relationship
+
         client.addListener("message", message);
-        client.users.addListener("mutation", relationship);
+        // client.users.addListener("mutation", relationship);
 
         return () => {
             client.removeListener("message", message);
-            client.users.removeListener("mutation", relationship);
+            // client.users.removeListener("mutation", relationship);
         };
     }, [client, playSound, guild_id, channel_id, showNotification, notifs]);
 
diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx
index 3a5ad2b2cbe4d207407f79e6628480507c55a4ee..be8acb38c62fa5e8614c8b9d02c36f74744f7c6a 100644
--- a/src/context/revoltjs/RevoltClient.tsx
+++ b/src/context/revoltjs/RevoltClient.tsx
@@ -8,7 +8,6 @@ import { useContext, useEffect, useMemo, useState } from "preact/hooks";
 
 import { SingletonMessageRenderer } from "../../lib/renderer/Singleton";
 
-import { useData } from "../../mobx/State";
 import { dispatch } from "../../redux";
 import { connectState } from "../../redux/connector";
 import { AuthState } from "../../redux/reducers/auth";
@@ -36,8 +35,6 @@ export interface ClientOperations {
     logout: (shouldRequest?: boolean) => Promise<void>;
     loggedIn: () => boolean;
     ready: () => boolean;
-
-    openDM: (user_id: string) => Promise<string>;
 }
 
 // By the time they are used, they should all be initialized.
@@ -53,7 +50,6 @@ type Props = {
 };
 
 function Context({ auth, children }: Props) {
-    const history = useHistory();
     const { openScreen } = useIntermediate();
     const [status, setStatus] = useState(ClientStatus.INIT);
     const [client, setClient] = useState<Client>(
@@ -89,7 +85,6 @@ function Context({ auth, children }: Props) {
                 autoReconnect: false,
                 apiURL: import.meta.env.VITE_API_URL,
                 debug: import.meta.env.DEV,
-                db,
             });
 
             setClient(client);
@@ -150,11 +145,6 @@ function Context({ auth, children }: Props) {
             loggedIn: () => typeof auth.active !== "undefined",
             ready: () =>
                 operations.loggedIn() && typeof client.user !== "undefined",
-            openDM: async (user_id: string) => {
-                const channel = await client.users.openDM(user_id);
-                history.push(`/channel/${channel!._id}`);
-                return channel!._id;
-            },
         };
     }, [client, auth.active]);
 
@@ -165,10 +155,6 @@ function Context({ auth, children }: Props) {
 
     useEffect(() => {
         (async () => {
-            if (client.db) {
-                await client.restore();
-            }
-
             if (auth.active) {
                 dispatch({ type: "QUEUE_FAIL_ALL" });
 
diff --git a/src/context/revoltjs/StateMonitor.tsx b/src/context/revoltjs/StateMonitor.tsx
index 3ec2d146bf58634e095295249fd50218cf5116e1..bc235fc9ba7e497cdf1784f7e1abd8a890b503c7 100644
--- a/src/context/revoltjs/StateMonitor.tsx
+++ b/src/context/revoltjs/StateMonitor.tsx
@@ -1,7 +1,7 @@
 /**
  * This file monitors the message cache to delete any queued messages that have already sent.
  */
-import { Message } from "revolt.js";
+import { Message } from "revolt.js/dist/maps/Messages";
 
 import { useContext, useEffect } from "preact/hooks";
 
diff --git a/src/context/revoltjs/SyncManager.tsx b/src/context/revoltjs/SyncManager.tsx
index ca7bb5bdb92cea995f9597e5ba5735b74deb345d..e734234fd1c1d2236d0415953401e0845a55689d 100644
--- a/src/context/revoltjs/SyncManager.tsx
+++ b/src/context/revoltjs/SyncManager.tsx
@@ -2,7 +2,7 @@
  * This file monitors changes to settings and syncs them to the server.
  */
 import isEqual from "lodash.isequal";
-import { Sync } from "revolt.js/dist/api/objects";
+import { UserSettings } from "revolt-api/types/Sync";
 import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
 
 import { useContext, useEffect } from "preact/hooks";
@@ -31,7 +31,7 @@ type Props = {
 const lastValues: { [key in SyncKeys]?: any } = {};
 
 export function mapSync(
-    packet: Sync.UserSettings,
+    packet: UserSettings,
     revision?: Record<string, number>,
 ) {
     const update: { [key in SyncKeys]?: [number, SyncData[key]] } = {};
diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts
index a84e07ad5b4099639d9fab289cedbe6ad2cf2803..1fe2907e9b450d9c9a52d71cea2d2622213b8c49 100644
--- a/src/context/revoltjs/events.ts
+++ b/src/context/revoltjs/events.ts
@@ -1,10 +1,9 @@
-import { Client, Message } from "revolt.js/dist";
+import { Client } from "revolt.js/dist";
+import { Message } from "revolt.js/dist/maps/Messages";
 import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
 
 import { StateUpdater } from "preact/hooks";
 
-import { DataStore } from "../../mobx";
-import { useData } from "../../mobx/State";
 import { dispatch } from "../../redux";
 
 import { ClientOperations, ClientStatus } from "./RevoltClient";
@@ -78,10 +77,10 @@ export function registerEvents(
         },
 
         message: (message: Message) => {
-            if (message.mentions?.includes(client.user!._id)) {
+            if (message.mention_ids?.includes(client.user!._id)) {
                 dispatch({
                     type: "UNREADS_MENTION",
-                    channel: message.channel,
+                    channel: message.channel_id,
                     message: message._id,
                 });
             }
@@ -110,13 +109,6 @@ export function registerEvents(
         console.log("(o) Object mutated", target, "\nChanged:", key);
     }
 
-    if (import.meta.env.DEV) {
-        client.users.addListener("mutation", logMutation);
-        client.servers.addListener("mutation", logMutation);
-        client.channels.addListener("mutation", logMutation);
-        client.members.addListener("mutation", logMutation);
-    }
-
     const online = () => {
         if (operations.ready()) {
             setStatus(ClientStatus.RECONNECTING);
@@ -144,13 +136,6 @@ export function registerEvents(
             );
         }
 
-        if (import.meta.env.DEV) {
-            client.users.removeListener("mutation", logMutation);
-            client.servers.removeListener("mutation", logMutation);
-            client.channels.removeListener("mutation", logMutation);
-            client.members.removeListener("mutation", logMutation);
-        }
-
         window.removeEventListener("online", online);
         window.removeEventListener("offline", offline);
     };
diff --git a/src/context/revoltjs/hooks.ts b/src/context/revoltjs/hooks.ts
deleted file mode 100644
index 59edf36699ca77526b07d3040cb978c615b77c78..0000000000000000000000000000000000000000
--- a/src/context/revoltjs/hooks.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Client, PermissionCalculator } from "revolt.js";
-
-import { useContext, useEffect, useState } from "preact/hooks";
-
-//#region Hooks v1 (deprecated)
-import { AppContext } from "./RevoltClient";
-
-export interface HookContext {
-    client: Client;
-    forceUpdate: () => void;
-}
-
-export function useForceUpdate(context?: HookContext): HookContext {
-    const client = useContext(AppContext);
-    if (context) return context;
-
-    const H = useState(0);
-    let updateState: (_: number) => void;
-    if (Array.isArray(H)) {
-        const [, u] = H;
-        updateState = u;
-    } else {
-        console.warn("Failed to construct using useState.");
-        updateState = () => {};
-    }
-
-    return { client, forceUpdate: () => updateState(Math.random()) };
-}
-
-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]);
-
-    const calculator = new PermissionCalculator(ctx.client);
-    return calculator.forUser(id);
-}
-
-export function useChannelPermission(id: string, context?: HookContext) {
-    const ctx = useForceUpdate(context);
-
-    const channel = ctx.client.channels.get(id);
-    const server =
-        channel &&
-        (channel.channel_type === "TextChannel" ||
-            channel.channel_type === "VoiceChannel")
-            ? channel.server
-            : undefined;
-
-    const mutation = (target: string) => target === id && ctx.forceUpdate();
-    const mutationServer = (target: string) =>
-        target === server && ctx.forceUpdate();
-    const mutationMember = (target: string) =>
-        target.substr(26) === ctx.client.user!._id && ctx.forceUpdate();
-
-    useEffect(() => {
-        ctx.client.channels.addListener("update", mutation);
-
-        if (server) {
-            ctx.client.servers.addListener("update", mutationServer);
-            ctx.client.members.addListener("update", mutationMember);
-        }
-
-        return () => {
-            ctx.client.channels.removeListener("update", mutation);
-
-            if (server) {
-                ctx.client.servers.removeListener("update", mutationServer);
-                ctx.client.members.removeListener("update", mutationMember);
-            }
-        };
-    }, [id]);
-
-    const 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();
-    const mutationMember = (target: string) =>
-        target.substr(26) === ctx.client.user!._id && ctx.forceUpdate();
-
-    useEffect(() => {
-        ctx.client.servers.addListener("update", mutation);
-        ctx.client.members.addListener("update", mutationMember);
-
-        return () => {
-            ctx.client.servers.removeListener("update", mutation);
-            ctx.client.members.removeListener("update", mutationMember);
-        };
-    }, [id]);
-
-    const calculator = new PermissionCalculator(ctx.client);
-    return calculator.forServer(id);
-}
-//#endregion
diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx
index bc48ac90ec286f79a00ec5b3913350b3d4d07dfe..b89b7e88a78d26a9aaf423af6e6f7137b8fe7b54 100644
--- a/src/lib/ContextMenus.tsx
+++ b/src/lib/ContextMenus.tsx
@@ -12,18 +12,17 @@ import {
 } from "@styled-icons/boxicons-regular";
 import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
 import { useHistory } from "react-router-dom";
-import {
-    Attachment,
-    Channels,
-    Message,
-    Servers,
-    Users,
-} from "revolt.js/dist/api/objects";
+import { Attachment } from "revolt-api/types/Autumn";
+import { Presence, RelationshipStatus } from "revolt-api/types/Users";
 import {
     ChannelPermission,
     ServerPermission,
     UserPermission,
 } from "revolt.js/dist/api/permissions";
+import { Channel } from "revolt.js/dist/maps/Channels";
+import { Message } from "revolt.js/dist/maps/Messages";
+import { Server } from "revolt.js/dist/maps/Servers";
+import { User } from "revolt.js/dist/maps/Users";
 
 import {
     ContextMenu,
@@ -34,8 +33,6 @@ import {
 import { Text } from "preact-i18n";
 import { useContext } from "preact/hooks";
 
-import { Channel, Server, User } from "../mobx";
-import { useData } from "../mobx/State";
 import { dispatch } from "../redux";
 import { connectState } from "../redux/connector";
 import {
@@ -52,12 +49,6 @@ import {
     StatusContext,
     useClient,
 } from "../context/revoltjs/RevoltClient";
-import {
-    useChannelPermission,
-    useForceUpdate,
-    useServerPermission,
-    useUserPermission,
-} from "../context/revoltjs/hooks";
 import { takeError } from "../context/revoltjs/util";
 
 import Tooltip from "../components/common/Tooltip";
@@ -91,13 +82,13 @@ type Action =
     | { action: "reply_message"; id: string }
     | { action: "quote_message"; content: string }
     | { action: "edit_message"; id: string }
-    | { action: "delete_message"; target: Channels.Message }
+    | { action: "delete_message"; target: Message }
     | { action: "open_file"; attachment: Attachment }
     | { action: "save_file"; attachment: Attachment }
     | { action: "copy_file_link"; attachment: Attachment }
     | { action: "open_link"; link: string }
     | { action: "copy_link"; link: string }
-    | { action: "remove_member"; channel: string; user: User }
+    | { action: "remove_member"; channel: Channel; user: User }
     | { action: "kick_member"; target: Server; user: User }
     | { action: "ban_member"; target: Server; user: User }
     | { action: "view_profile"; user: User }
@@ -107,7 +98,7 @@ type Action =
     | { action: "add_friend"; user: User }
     | { action: "remove_friend"; user: User }
     | { action: "cancel_friend"; user: User }
-    | { action: "set_presence"; presence: Users.Presence }
+    | { action: "set_presence"; presence: Presence }
     | { action: "set_status" }
     | { action: "clear_status" }
     | { action: "create_channel"; target: Server }
@@ -196,7 +187,8 @@ function ContextMenus(props: Props) {
                             });
 
                         client.channels
-                            .sendMessage(data.message.channel, {
+                            .get(data.message.channel)!
+                            .sendMessage({
                                 nonce: data.message.id,
                                 content: data.message.data.content as string,
                                 replies: data.message.data.replies,
@@ -313,10 +305,7 @@ function ContextMenus(props: Props) {
 
                 case "remove_member":
                     {
-                        client.channels.removeMember(
-                            data.channel,
-                            data.user._id,
-                        );
+                        data.channel.removeMember(data.user._id);
                     }
                     break;
 
@@ -326,9 +315,7 @@ function ContextMenus(props: Props) {
 
                 case "message_user":
                     {
-                        const channel = await client.users.openDM(
-                            data.user._id,
-                        );
+                        const channel = await data.user.openDM();
                         if (channel) {
                             history.push(`/channel/${channel._id}`);
                         }
@@ -337,7 +324,7 @@ function ContextMenus(props: Props) {
 
                 case "add_friend":
                     {
-                        await client.users.addFriend(data.user.username);
+                        await data.user.addFriend();
                     }
                     break;
 
@@ -349,7 +336,7 @@ function ContextMenus(props: Props) {
                     });
                     break;
                 case "unblock_user":
-                    await client.users.unblockUser(data.user._id);
+                    await data.user.unblockUser();
                     break;
                 case "remove_friend":
                     openScreen({
@@ -359,12 +346,12 @@ function ContextMenus(props: Props) {
                     });
                     break;
                 case "cancel_friend":
-                    await client.users.removeFriend(data.user._id);
+                    await data.user.removeFriend();
                     break;
 
                 case "set_presence":
                     {
-                        await client.users.editUser({
+                        await client.users.edit({
                             status: {
                                 ...client.user?.status,
                                 presence: data.presence,
@@ -383,7 +370,7 @@ function ContextMenus(props: Props) {
                 case "clear_status":
                     {
                         const { text, ...status } = client.user?.status ?? {};
-                        await client.users.editUser({ status });
+                        await client.users.edit({ status });
                     }
                     break;
 
@@ -463,9 +450,6 @@ function ContextMenus(props: Props) {
                     unread,
                     contextualChannel: cxid,
                 }: ContextMenuData) => {
-                    const store = useData();
-
-                    const forceUpdate = useForceUpdate();
                     const elements: Children[] = [];
                     let lastDivider = false;
 
@@ -495,11 +479,8 @@ function ContextMenus(props: Props) {
                     }
 
                     if (server_list) {
-                        const server = store.servers.get(server_list);
-                        const permissions = useServerPermission(
-                            server_list,
-                            forceUpdate,
-                        );
+                        const server = client.servers.get(server_list)!;
+                        const permissions = server.permission;
                         if (server) {
                             if (permissions & ServerPermission.ManageChannels)
                                 generateAction({
@@ -526,13 +507,13 @@ function ContextMenus(props: Props) {
                         pushDivider();
                     }
 
-                    const channel = cid ? store.channels.get(cid) : undefined;
+                    const channel = cid ? client.channels.get(cid) : undefined;
                     const contextualChannel = cxid
-                        ? store.channels.get(cxid)
+                        ? client.channels.get(cxid)
                         : undefined;
                     const targetChannel = channel ?? contextualChannel;
 
-                    const user = uid ? store.users.get(uid) : undefined;
+                    const user = uid ? client.users.get(uid) : undefined;
                     const serverChannel =
                         targetChannel &&
                         (targetChannel.channel_type === "TextChannel" ||
@@ -540,23 +521,17 @@ function ContextMenus(props: Props) {
                             ? targetChannel
                             : undefined;
 
-                    const s = serverChannel ? serverChannel.server! : sid;
-                    const server = s ? store.servers.get(s) : undefined;
-
-                    const channelPermissions = targetChannel
-                        ? useChannelPermission(targetChannel._id, forceUpdate)
-                        : 0;
-                    const serverPermissions = server
-                        ? useServerPermission(server._id, forceUpdate)
-                        : serverChannel
-                        ? useServerPermission(
-                              serverChannel.server!,
-                              forceUpdate,
-                          )
-                        : 0;
-                    const userPermissions = user
-                        ? useUserPermission(user._id, forceUpdate)
-                        : 0;
+                    const s = serverChannel ? serverChannel.server_id! : sid;
+                    const server = s ? client.servers.get(s) : undefined;
+
+                    const channelPermissions = targetChannel?.permission || 0;
+                    const serverPermissions =
+                        (server
+                            ? server.permission
+                            : serverChannel
+                            ? serverChannel.server?.permission
+                            : 0) || 0;
+                    const userPermissions = (user ? user.permission : 0) || 0;
 
                     if (channel && unread) {
                         generateAction({ action: "mark_as_read", channel });
@@ -576,29 +551,29 @@ function ContextMenus(props: Props) {
                     if (user) {
                         let actions: Action["action"][];
                         switch (user.relationship) {
-                            case Users.Relationship.User:
+                            case RelationshipStatus.User:
                                 actions = [];
                                 break;
-                            case Users.Relationship.Friend:
+                            case RelationshipStatus.Friend:
                                 actions = ["remove_friend", "block_user"];
                                 break;
-                            case Users.Relationship.Incoming:
+                            case RelationshipStatus.Incoming:
                                 actions = [
                                     "add_friend",
                                     "cancel_friend",
                                     "block_user",
                                 ];
                                 break;
-                            case Users.Relationship.Outgoing:
+                            case RelationshipStatus.Outgoing:
                                 actions = ["cancel_friend", "block_user"];
                                 break;
-                            case Users.Relationship.Blocked:
+                            case RelationshipStatus.Blocked:
                                 actions = ["unblock_user"];
                                 break;
-                            case Users.Relationship.BlockedOther:
+                            case RelationshipStatus.BlockedOther:
                                 actions = ["block_user"];
                                 break;
-                            case Users.Relationship.None:
+                            case RelationshipStatus.None:
                             default:
                                 actions = ["add_friend", "block_user"];
                         }
@@ -629,12 +604,12 @@ function ContextMenus(props: Props) {
                     if (contextualChannel) {
                         if (contextualChannel.channel_type === "Group" && uid) {
                             if (
-                                contextualChannel.owner === userId &&
+                                contextualChannel.owner_id === userId &&
                                 userId !== uid
                             ) {
                                 generateAction({
                                     action: "remove_member",
-                                    channel: contextualChannel._id,
+                                    channel: contextualChannel,
                                     user: user!,
                                 });
                             }
@@ -697,7 +672,7 @@ function ContextMenus(props: Props) {
                             });
                         }
 
-                        if (message.author === userId) {
+                        if (message.author_id === userId) {
                             generateAction({
                                 action: "edit_message",
                                 id: message._id,
@@ -705,7 +680,7 @@ function ContextMenus(props: Props) {
                         }
 
                         if (
-                            message.author === userId ||
+                            message.author_id === userId ||
                             channelPermissions &
                                 ChannelPermission.ManageMessages
                         ) {
@@ -820,7 +795,7 @@ function ContextMenus(props: Props) {
                                         generateAction(
                                             {
                                                 action: "open_server_channel_settings",
-                                                server: channel.server!,
+                                                server: channel.server_id!,
                                                 id: channel._id,
                                             },
                                             "open_channel_settings",
@@ -885,9 +860,7 @@ function ContextMenus(props: Props) {
                 onClose={contextClick}
                 className="Status">
                 {() => {
-                    const store = useData();
-                    const user = store.users.get(client.user!._id)!;
-
+                    const user = client.user!;
                     return (
                         <>
                             <div className="header">
@@ -927,7 +900,7 @@ function ContextMenus(props: Props) {
                             <MenuItem
                                 data={{
                                     action: "set_presence",
-                                    presence: Users.Presence.Online,
+                                    presence: Presence.Online,
                                 }}
                                 disabled={!isOnline}>
                                 <div className="indicator online" />
@@ -936,7 +909,7 @@ function ContextMenus(props: Props) {
                             <MenuItem
                                 data={{
                                     action: "set_presence",
-                                    presence: Users.Presence.Idle,
+                                    presence: Presence.Idle,
                                 }}
                                 disabled={!isOnline}>
                                 <div className="indicator idle" />
@@ -945,7 +918,7 @@ function ContextMenus(props: Props) {
                             <MenuItem
                                 data={{
                                     action: "set_presence",
-                                    presence: Users.Presence.Busy,
+                                    presence: Presence.Busy,
                                 }}
                                 disabled={!isOnline}>
                                 <div className="indicator busy" />
@@ -954,7 +927,7 @@ function ContextMenus(props: Props) {
                             <MenuItem
                                 data={{
                                     action: "set_presence",
-                                    presence: Users.Presence.Invisible,
+                                    presence: Presence.Invisible,
                                 }}
                                 disabled={!isOnline}>
                                 <div className="indicator invisible" />
@@ -982,7 +955,7 @@ function ContextMenus(props: Props) {
             <ContextMenuWithData
                 id="NotificationOptions"
                 onClose={contextClick}>
-                {({ channel }: { channel: Channels.Channel }) => {
+                {({ channel }: { channel: Channel }) => {
                     const state = props.notifications[channel._id];
                     const actual = getNotificationState(
                         props.notifications,
diff --git a/src/lib/renderer/Singleton.ts b/src/lib/renderer/Singleton.ts
index e3f2b0e630496e9648fe7040420465a3fcb1159d..21eafefd89b3bb0d6d326fbf92677bcecedfcfe4 100644
--- a/src/lib/renderer/Singleton.ts
+++ b/src/lib/renderer/Singleton.ts
@@ -1,5 +1,6 @@
 import EventEmitter3 from "eventemitter3";
-import { Client, Message } from "revolt.js";
+import { Client } from "revolt.js";
+import { Message } from "revolt.js/dist/maps/Messages";
 
 import { useEffect, useState } from "preact/hooks";
 
diff --git a/src/lib/renderer/simple/SimpleRenderer.ts b/src/lib/renderer/simple/SimpleRenderer.ts
index 5caca2c4802607cbf24507944f5b7d38a690e90b..87df4aa154f923bd52b5db2c86d6c0d3cc4e1dfe 100644
--- a/src/lib/renderer/simple/SimpleRenderer.ts
+++ b/src/lib/renderer/simple/SimpleRenderer.ts
@@ -1,5 +1,3 @@
-import { mapMessage } from "../../../context/revoltjs/util";
-
 import { SMOOTH_SCROLL_ON_RECEIVE } from "../Singleton";
 import { RendererRoutines } from "../types";
 
@@ -8,14 +6,10 @@ export const SimpleRenderer: RendererRoutines = {
         if (renderer.client!.websocket.connected) {
             if (nearby)
                 renderer
-                    .client!.channels.fetchMessagesWithUsers(
-                        id,
-                        { nearby, limit: 100 },
-                        true,
-                    )
-                    .then(({ messages: data }) => {
-                        data.sort((a, b) => a._id.localeCompare(b._id));
-                        const messages = data.map((x) => mapMessage(x));
+                    .client!.channels.get(id)!
+                    .fetchMessagesWithUsers({ nearby, limit: 100 })
+                    .then(({ messages }) => {
+                        messages.sort((a, b) => a._id.localeCompare(b._id));
                         renderer.setState(
                             id,
                             {
@@ -29,16 +23,16 @@ export const SimpleRenderer: RendererRoutines = {
                     });
             else
                 renderer
-                    .client!.channels.fetchMessagesWithUsers(id, {}, true)
-                    .then(({ messages: data }) => {
-                        data.reverse();
-                        const messages = data.map((x) => mapMessage(x));
+                    .client!.channels.get(id)!
+                    .fetchMessagesWithUsers({})
+                    .then(({ messages }) => {
+                        messages.reverse();
                         renderer.setState(
                             id,
                             {
                                 type: "RENDER",
                                 messages,
-                                atTop: data.length < 50,
+                                atTop: messages.length < 50,
                                 atBottom: true,
                             },
                             { type: "ScrollToBottom", smooth },
@@ -54,7 +48,7 @@ export const SimpleRenderer: RendererRoutines = {
         if (renderer.state.messages.find((x) => x._id === message._id)) return;
         if (!renderer.state.atBottom) return;
 
-        let messages = [...renderer.state.messages, mapMessage(message)];
+        let messages = [...renderer.state.messages, message];
         let atTop = renderer.state.atTop;
         if (messages.length > 150) {
             messages = messages.slice(messages.length - 150);
@@ -62,7 +56,7 @@ export const SimpleRenderer: RendererRoutines = {
         }
 
         renderer.setState(
-            message.channel,
+            message.channel_id,
             {
                 ...renderer.state,
                 messages,
@@ -72,7 +66,8 @@ export const SimpleRenderer: RendererRoutines = {
         );
     },
     edit: async (renderer, id, patch) => {
-        const channel = renderer.channel;
+        // ! FIXME: verify if this is needed anymore
+        /*const channel = renderer.channel;
         if (!channel) return;
         if (renderer.state.type !== "RENDER") return;
 
@@ -91,7 +86,7 @@ export const SimpleRenderer: RendererRoutines = {
                 },
                 { type: "StayAtBottom" },
             );
-        }
+        }*/
     },
     delete: async (renderer, id) => {
         const channel = renderer.channel;
@@ -122,14 +117,11 @@ export const SimpleRenderer: RendererRoutines = {
         if (state.type !== "RENDER") return;
         if (state.atTop) return;
 
-        const { messages: data } =
-            await renderer.client!.channels.fetchMessagesWithUsers(
-                channel,
-                {
-                    before: state.messages[0]._id,
-                },
-                true,
-            );
+        const { messages: data } = await renderer
+            .client!.channels.get(channel)!
+            .fetchMessagesWithUsers({
+                before: state.messages[0]._id,
+            });
 
         if (data.length === 0) {
             return renderer.setState(channel, {
@@ -139,7 +131,7 @@ export const SimpleRenderer: RendererRoutines = {
         }
 
         data.reverse();
-        let messages = [...data.map((x) => mapMessage(x)), ...state.messages];
+        let messages = [...data, ...state.messages];
 
         let atTop = false;
         if (data.length < 50) {
@@ -166,15 +158,12 @@ export const SimpleRenderer: RendererRoutines = {
         if (state.type !== "RENDER") return;
         if (state.atBottom) return;
 
-        const { messages: data } =
-            await renderer.client!.channels.fetchMessagesWithUsers(
-                channel,
-                {
-                    after: state.messages[state.messages.length - 1]._id,
-                    sort: "Oldest",
-                },
-                true,
-            );
+        const { messages: data } = await renderer
+            .client!.channels.get(channel)!
+            .fetchMessagesWithUsers({
+                after: state.messages[state.messages.length - 1]._id,
+                sort: "Oldest",
+            });
 
         if (data.length === 0) {
             return renderer.setState(channel, {
@@ -183,7 +172,7 @@ export const SimpleRenderer: RendererRoutines = {
             });
         }
 
-        let messages = [...state.messages, ...data.map((x) => mapMessage(x))];
+        let messages = [...state.messages, ...data];
 
         let atBottom = false;
         if (data.length < 50) {
diff --git a/src/lib/renderer/types.ts b/src/lib/renderer/types.ts
index a85e1cd60041926bb02cc78419ed6e227a0d64d6..61d830f19873d1e9cbdde9d23f3ee3c121450bd3 100644
--- a/src/lib/renderer/types.ts
+++ b/src/lib/renderer/types.ts
@@ -1,6 +1,4 @@
-import { Message } from "revolt.js";
-
-import { MessageObject } from "../../context/revoltjs/util";
+import { Message } from "revolt.js/dist/maps/Messages";
 
 import { SingletonRenderer } from "./Singleton";
 
@@ -20,7 +18,7 @@ export type RenderState =
           type: "RENDER";
           atTop: boolean;
           atBottom: boolean;
-          messages: MessageObject[];
+          messages: Message[];
       };
 
 export interface RendererRoutines {
diff --git a/src/pages/Open.tsx b/src/pages/Open.tsx
index ddeb98b684c6f4db372c24f094b3ca000ebc9464..e297a419c3a0be995bec79e04a1360bad073913c 100644
--- a/src/pages/Open.tsx
+++ b/src/pages/Open.tsx
@@ -29,15 +29,15 @@ export default function Open() {
 
     useEffect(() => {
         if (id === "saved") {
-            for (const channel of client.channels.toArray()) {
+            for (const channel of [...client.channels.values()]) {
                 if (channel?.channel_type === "SavedMessages") {
                     history.push(`/channel/${channel._id}`);
                     return;
                 }
             }
 
-            client.users
-                .openDM(client.user?._id as string)
+            client
+                .user!.openDM()
                 .then((channel) => history.push(`/channel/${channel?._id}`))
                 .catch((error) => openScreen({ id: "error", error }));
 
@@ -46,19 +46,20 @@ export default function Open() {
 
         let user = client.users.get(id);
         if (user) {
-            const channel: string | undefined = client.channels
-                .toArray()
-                .find(
-                    (channel) =>
-                        channel?.channel_type === "DirectMessage" &&
-                        channel.recipients.includes(id),
-                )?._id;
+            const channel: string | undefined = [
+                ...client.channels.values(),
+            ].find(
+                (channel) =>
+                    channel?.channel_type === "DirectMessage" &&
+                    channel.recipient_ids!.includes(id),
+            )?._id;
 
             if (channel) {
                 history.push(`/channel/${channel}`);
             } else {
                 client.users
-                    .openDM(id)
+                    .get(id)
+                    ?.openDM()
                     .then((channel) => history.push(`/channel/${channel?._id}`))
                     .catch((error) => openScreen({ id: "error", error }));
             }
diff --git a/src/pages/channels/Channel.tsx b/src/pages/channels/Channel.tsx
index 9f40f8eaab8e7afcbcb7e628c2d5f799928a806b..b9846d0a94ac6a77031bc533590e926eb6d5e2bf 100644
--- a/src/pages/channels/Channel.tsx
+++ b/src/pages/channels/Channel.tsx
@@ -1,16 +1,16 @@
 import { observer } from "mobx-react-lite";
-import { useParams, useHistory } from "react-router-dom";
-import { Channels } from "revolt.js/dist/api/objects";
+import { useParams } from "react-router-dom";
+import { Channel as ChannelI } from "revolt.js/dist/maps/Channels";
 import styled from "styled-components";
 
 import { useState } from "preact/hooks";
 
 import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
 
-import { Channel as MobXChannel } from "../../mobx";
-import { useData } from "../../mobx/State";
 import { dispatch, getState } from "../../redux";
 
+import { useClient } from "../../context/revoltjs/RevoltClient";
+
 import AgeGate from "../../components/common/AgeGate";
 import MessageBox from "../../components/common/messaging/MessageBox";
 import JumpToBottom from "../../components/common/messaging/bars/JumpToBottom";
@@ -37,8 +37,8 @@ const ChannelContent = styled.div`
 `;
 
 export function Channel({ id }: { id: string }) {
-    const store = useData();
-    const channel = store.channels.get(id);
+    const client = useClient();
+    const channel = client.channels.get(id);
     if (!channel) return null;
 
     if (channel.channel_type === "VoiceChannel") {
@@ -49,7 +49,7 @@ export function Channel({ id }: { id: string }) {
 }
 
 const MEMBERS_SIDEBAR_KEY = "sidebar_members";
-const TextChannel = observer(({ channel }: { channel: MobXChannel }) => {
+const TextChannel = observer(({ channel }: { channel: ChannelI }) => {
     const [showMembers, setMembers] = useState(
         getState().sectionToggle[MEMBERS_SIDEBAR_KEY] ?? true,
     );
@@ -101,7 +101,7 @@ const TextChannel = observer(({ channel }: { channel: MobXChannel }) => {
     );
 });
 
-function VoiceChannel({ channel }: { channel: MobXChannel }) {
+function VoiceChannel({ channel }: { channel: ChannelI }) {
     return (
         <>
             <ChannelHeader channel={channel} />
diff --git a/src/pages/channels/ChannelHeader.tsx b/src/pages/channels/ChannelHeader.tsx
index f14ac5127c7ea74a0842639499430fe1683ae708..ae2c188154468ab05f9af96de44196f2c3af91ae 100644
--- a/src/pages/channels/ChannelHeader.tsx
+++ b/src/pages/channels/ChannelHeader.tsx
@@ -1,18 +1,13 @@
 import { At, Hash, Menu } from "@styled-icons/boxicons-regular";
 import { Notepad, Group } from "@styled-icons/boxicons-solid";
-import { observable } from "mobx";
 import { observer } from "mobx-react-lite";
+import { Channel } from "revolt.js/dist/maps/Channels";
+import { User } from "revolt.js/dist/maps/Users";
 import styled from "styled-components";
 
-import { useContext } from "preact/hooks";
-
 import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
 
-import { Channel, User } from "../../mobx";
-import { useData } from "../../mobx/State";
-
 import { useIntermediate } from "../../context/intermediate/Intermediate";
-import { AppContext, useClient } from "../../context/revoltjs/RevoltClient";
 import { getChannelName } from "../../context/revoltjs/util";
 
 import { useStatusColour } from "../../components/common/user/UserIcon";
@@ -71,10 +66,8 @@ const Info = styled.div`
 
 export default observer(({ channel, toggleSidebar }: ChannelHeaderProps) => {
     const { openScreen } = useIntermediate();
-    const client = useClient();
-    const state = useData();
 
-    const name = getChannelName(client, channel);
+    const name = getChannelName(channel);
     let icon, recipient: User | undefined;
     switch (channel.channel_type) {
         case "SavedMessages":
@@ -82,8 +75,7 @@ export default observer(({ channel, toggleSidebar }: ChannelHeaderProps) => {
             break;
         case "DirectMessage":
             icon = <At size={24} />;
-            const uid = client.channels.getRecipient(channel._id);
-            recipient = state.users.get(uid);
+            recipient = channel.recipient;
             break;
         case "Group":
             icon = <Group size={24} />;
diff --git a/src/pages/channels/actions/HeaderActions.tsx b/src/pages/channels/actions/HeaderActions.tsx
index b7eb775c5a6db3a95c4dc2c92bc27412ee66c6ab..e3edd59fe698f853a9efdda72741a2fda4751d4d 100644
--- a/src/pages/channels/actions/HeaderActions.tsx
+++ b/src/pages/channels/actions/HeaderActions.tsx
@@ -29,7 +29,6 @@ export default function HeaderActions({
     toggleSidebar,
 }: ChannelHeaderProps) {
     const { openScreen } = useIntermediate();
-    const client = useContext(AppContext);
     const history = useHistory();
 
     return (
@@ -41,13 +40,10 @@ export default function HeaderActions({
                         onClick={() =>
                             openScreen({
                                 id: "user_picker",
-                                omit: channel.recipients!,
+                                omit: channel.recipient_ids!,
                                 callback: async (users) => {
                                     for (const user of users) {
-                                        await client.channels.addMember(
-                                            channel._id,
-                                            user,
-                                        );
+                                        await channel.addMember(user);
                                     }
                                 },
                             })
diff --git a/src/pages/channels/messaging/ConversationStart.tsx b/src/pages/channels/messaging/ConversationStart.tsx
index 447f24f091937fe931ac663c96b0aca8d92545ce..1d26bed65d1d3ee50a58b82e0ff19393db2cb095 100644
--- a/src/pages/channels/messaging/ConversationStart.tsx
+++ b/src/pages/channels/messaging/ConversationStart.tsx
@@ -3,8 +3,6 @@ import styled from "styled-components";
 
 import { Text } from "preact-i18n";
 
-import { useData } from "../../../mobx/State";
-
 import { useClient } from "../../../context/revoltjs/RevoltClient";
 import { getChannelName } from "../../../context/revoltjs/util";
 
@@ -28,14 +26,13 @@ interface Props {
 }
 
 export default observer(({ id }: Props) => {
-    const store = useData();
     const client = useClient();
-    const channel = store.channels.get(id);
+    const channel = client.channels.get(id);
     if (!channel) return null;
 
     return (
         <StartBase>
-            <h1>{getChannelName(client, channel, true)}</h1>
+            <h1>{getChannelName(channel, true)}</h1>
             <h4>
                 <Text id="app.main.channel.start.group" />
             </h4>
diff --git a/src/pages/channels/messaging/MessageEditor.tsx b/src/pages/channels/messaging/MessageEditor.tsx
index 305ca42dc0d1b23b4ef075051fde1e0b6aad0b02..19fdac97f3c0114b3fbe107610f678173dbe7a27 100644
--- a/src/pages/channels/messaging/MessageEditor.tsx
+++ b/src/pages/channels/messaging/MessageEditor.tsx
@@ -1,3 +1,4 @@
+import { Message } from "revolt.js/dist/maps/Messages";
 import styled from "styled-components";
 
 import { useContext, useEffect, useState } from "preact/hooks";
@@ -10,7 +11,6 @@ import {
     useIntermediate,
 } from "../../../context/intermediate/Intermediate";
 import { AppContext } from "../../../context/revoltjs/RevoltClient";
-import { MessageObject } from "../../../context/revoltjs/util";
 
 import AutoComplete, {
     useAutoComplete,
@@ -44,7 +44,7 @@ const EditorBase = styled.div`
 `;
 
 interface Props {
-    message: MessageObject;
+    message: Message;
     finish: () => void;
 }
 
@@ -52,7 +52,6 @@ export default function MessageEditor({ message, finish }: Props) {
     const [content, setContent] = useState((message.content as string) ?? "");
     const { focusTaken } = useContext(IntermediateContext);
     const { openScreen } = useIntermediate();
-    const client = useContext(AppContext);
 
     async function save() {
         finish();
@@ -60,13 +59,11 @@ export default function MessageEditor({ message, finish }: Props) {
         if (content.length === 0) {
             openScreen({
                 id: "special_prompt",
-                // @ts-expect-error
                 type: "delete_message",
-                // @ts-expect-error
                 target: message,
             });
         } else if (content !== message.content) {
-            await client.channels.editMessage(message.channel, message._id, {
+            await message.editMessage({
                 content,
             });
         }
diff --git a/src/pages/channels/messaging/MessageRenderer.tsx b/src/pages/channels/messaging/MessageRenderer.tsx
index a84998772d99a73361f61219f35ece46d5c2c923..c30d14d8ee9a0a9f7e7ed04afc30d60be3b1b452 100644
--- a/src/pages/channels/messaging/MessageRenderer.tsx
+++ b/src/pages/channels/messaging/MessageRenderer.tsx
@@ -1,5 +1,7 @@
 import { X } from "@styled-icons/boxicons-regular";
-import { Users } from "revolt.js/dist/api/objects";
+import { RelationshipStatus } from "revolt-api/types/Users";
+import { SYSTEM_USER_ID } from "revolt.js";
+import { Message as MessageObject } from "revolt.js/dist/maps/Messages";
 import styled from "styled-components";
 import { decodeTime } from "ulid";
 
@@ -15,7 +17,6 @@ import { QueuedMessage } from "../../../redux/reducers/queue";
 
 import RequiresOnline from "../../../context/revoltjs/RequiresOnline";
 import { AppContext } from "../../../context/revoltjs/RevoltClient";
-import { MessageObject } from "../../../context/revoltjs/util";
 
 import Message from "../../../components/common/messaging/Message";
 import { SystemMessage } from "../../../components/common/messaging/SystemMessage";
@@ -60,7 +61,7 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
         function editLast() {
             if (state.type !== "RENDER") return;
             for (let i = state.messages.length - 1; i >= 0; i--) {
-                if (state.messages[i].author === userId) {
+                if (state.messages[i].author_id === userId) {
                     setEditing(state.messages[i]._id);
                     internalEmit("MessageArea", "jump_to_bottom");
                     return;
@@ -129,10 +130,15 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
 
     for (const message of state.messages) {
         if (previous) {
-            compare(message._id, message.author, previous._id, previous.author);
+            compare(
+                message._id,
+                message.author_id,
+                previous._id,
+                previous.author_id,
+            );
         }
 
-        if (message.author === "00000000000000000000000000") {
+        if (message.author_id === SYSTEM_USER_ID) {
             render.push(
                 <SystemMessage
                     key={message._id}
@@ -143,10 +149,7 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
             );
         } else {
             // ! FIXME: temp solution
-            if (
-                client.users.get(message.author)?.relationship ===
-                Users.Relationship.Blocked
-            ) {
+            if (message.author?.relationship === RelationshipStatus.Blocked) {
                 blocked++;
             } else {
                 if (blocked > 0) pushBlocked();
@@ -183,7 +186,7 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
             if (nonces.includes(msg.id)) continue;
 
             if (previous) {
-                compare(msg.id, userId!, previous._id, previous.author);
+                compare(msg.id, userId!, previous._id, previous.author_id);
 
                 previous = {
                     _id: msg.id,
@@ -191,7 +194,8 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
                 } as any;
             }
 
-            render.push(
+            // ! FIXME: add queued messages back
+            /* render.push(
                 <Message
                     message={{
                         ...msg.data,
@@ -202,7 +206,7 @@ function MessageRenderer({ id, state, queue, highlight }: Props) {
                     head={head}
                     attachContext
                 />,
-            );
+            ); */
         }
     } else {
         render.push(
diff --git a/src/pages/channels/voice/VoiceHeader.tsx b/src/pages/channels/voice/VoiceHeader.tsx
index 2eac2bb18fa64075f933765bf7b5a8dbb09c1c2a..95cab99f1b593b4128ed938cb29c0f1d28064a17 100644
--- a/src/pages/channels/voice/VoiceHeader.tsx
+++ b/src/pages/channels/voice/VoiceHeader.tsx
@@ -6,8 +6,6 @@ import styled from "styled-components";
 import { Text } from "preact-i18n";
 import { useContext } from "preact/hooks";
 
-import { useData } from "../../../mobx/State";
-
 import {
     VoiceContext,
     VoiceOperationsContext,
@@ -77,14 +75,13 @@ export default observer(({ id }: Props) => {
     const { isProducing, startProducing, stopProducing, disconnect } =
         useContext(VoiceOperationsContext);
 
-    const store = useData();
     const client = useClient();
-    const self = store.users.get(client.user!._id);
+    const self = client.users.get(client.user!._id);
 
     //const ctx = useForceUpdate();
     //const self = useSelf(ctx);
     const keys = participants ? Array.from(participants.keys()) : undefined;
-    const users = keys?.map((key) => store.users.get(key));
+    const users = keys?.map((key) => client.users.get(key));
 
     return (
         <VoiceBase>
diff --git a/src/pages/developer/Developer.tsx b/src/pages/developer/Developer.tsx
index 562a41a4b486e12a808332eaa4439acc533ca8b6..fb07302693582cb46e7d3c21337c1335e0c661f2 100644
--- a/src/pages/developer/Developer.tsx
+++ b/src/pages/developer/Developer.tsx
@@ -1,7 +1,5 @@
 import { Wrench } from "@styled-icons/boxicons-solid";
-import { isObservable, isObservableProp } from "mobx";
 import { observer } from "mobx-react-lite";
-import { Channels } from "revolt.js/dist/api/objects";
 
 import { useContext } from "preact/hooks";
 
@@ -9,17 +7,13 @@ import PaintCounter from "../../lib/PaintCounter";
 import { TextReact } from "../../lib/i18n";
 
 import { AppContext } from "../../context/revoltjs/RevoltClient";
-import { useUserPermission } from "../../context/revoltjs/hooks";
 
-import UserIcon from "../../components/common/user/UserIcon";
 import Header from "../../components/ui/Header";
 
-import { useData } from "../../mobx/State";
-
 export default function Developer() {
     // const voice = useContext(VoiceContext);
     const client = useContext(AppContext);
-    const userPermission = useUserPermission(client.user!._id);
+    const userPermission = client.user!.permission;
 
     return (
         <div>
@@ -40,10 +34,6 @@ export default function Developer() {
                     fields={{ provider: <b>GAMING!</b> }}
                 />
             </div>
-            <ObserverTest />
-            <ObserverTest2 />
-            <ObserverTest3 />
-            <ObserverTest4 />
             <div style={{ padding: "16px" }}>
                 {/*<span>
                     <b>Voice Status:</b> {VoiceStatus[voice.status]}
@@ -62,67 +52,3 @@ export default function Developer() {
         </div>
     );
 }
-
-const ObserverTest = observer(() => {
-    const client = useContext(AppContext);
-    const store = useData();
-    return (
-        <div style={{ padding: "16px" }}>
-            <p>
-                username:{" "}
-                {store.users.get(client.user!._id)?.username ?? "no user!"}
-                <PaintCounter small />
-            </p>
-        </div>
-    );
-});
-
-const ObserverTest2 = observer(() => {
-    const client = useContext(AppContext);
-    const store = useData();
-    return (
-        <div style={{ padding: "16px" }}>
-            <p>
-                status:{" "}
-                {JSON.stringify(store.users.get(client.user!._id)?.status) ??
-                    "none"}
-                <PaintCounter small />
-            </p>
-        </div>
-    );
-});
-
-const ObserverTest3 = observer(() => {
-    const client = useContext(AppContext);
-    const store = useData();
-    return (
-        <div style={{ padding: "16px" }}>
-            <p>
-                avatar{" "}
-                <UserIcon
-                    size={64}
-                    attachment={
-                        store.users.get(client.user!._id)?.avatar ?? undefined
-                    }
-                />
-                <PaintCounter small />
-            </p>
-        </div>
-    );
-});
-
-const ObserverTest4 = observer(() => {
-    const client = useContext(AppContext);
-    const store = useData();
-    return (
-        <div style={{ padding: "16px" }}>
-            <p>
-                status text:{" "}
-                {JSON.stringify(
-                    store.users.get(client.user!._id)?.status?.text,
-                ) ?? "none"}
-                <PaintCounter small />
-            </p>
-        </div>
-    );
-});
diff --git a/src/pages/friends/Friend.tsx b/src/pages/friends/Friend.tsx
index 38ec535f0e8dc5d4198058f7d86dcf2bce4c2eba..219f613fcb5a4ba49b7db16827f7586bced575bf 100644
--- a/src/pages/friends/Friend.tsx
+++ b/src/pages/friends/Friend.tsx
@@ -1,6 +1,7 @@
 import { X, Plus } from "@styled-icons/boxicons-regular";
 import { PhoneCall, Envelope, UserX } from "@styled-icons/boxicons-solid";
 import { observer } from "mobx-react-lite";
+import { useHistory } from "react-router-dom";
 import { RelationshipStatus } from "revolt-api/types/Users";
 import { User } from "revolt.js/dist/maps/Users";
 
@@ -30,9 +31,8 @@ interface Props {
 }
 
 export const Friend = observer(({ user }: Props) => {
-    const client = useContext(AppContext);
+    const history = useHistory();
     const { openScreen } = useIntermediate();
-    const { openDM } = useContext(OperationsContext);
     const { connect } = useContext(VoiceOperationsContext);
 
     const actions: Children[] = [];
@@ -46,14 +46,29 @@ export const Friend = observer(({ user }: Props) => {
                     type="circle"
                     className={classNames(styles.button, styles.success)}
                     onClick={(ev) =>
-                        stopPropagation(ev, openDM(user._id).then(connect))
+                        stopPropagation(
+                            ev,
+                            user.openDM().then((channel) => {
+                                connect(channel._id);
+                                history.push(`/channel/${channel._id}`);
+                            }),
+                        )
                     }>
                     <PhoneCall size={20} />
                 </IconButton>
                 <IconButton
                     type="circle"
                     className={styles.button}
-                    onClick={(ev) => stopPropagation(ev, openDM(user._id))}>
+                    onClick={(ev) =>
+                        stopPropagation(
+                            ev,
+                            user
+                                .openDM()
+                                .then((channel) =>
+                                    history.push(`/channel/${channel._id}`),
+                                ),
+                        )
+                    }>
                     <Envelope size={20} />
                 </IconButton>
             </>,
diff --git a/src/pages/settings/panes/Account.tsx b/src/pages/settings/panes/Account.tsx
index 867c659db97c7089d1c2342071aea04b4ce9f85e..e0af6836a3b31af4953b9f7113a18208e15173dd 100644
--- a/src/pages/settings/panes/Account.tsx
+++ b/src/pages/settings/panes/Account.tsx
@@ -14,7 +14,6 @@ import {
     StatusContext,
     useClient,
 } from "../../../context/revoltjs/RevoltClient";
-import { useForceUpdate } from "../../../context/revoltjs/hooks";
 
 import Tooltip from "../../../components/common/Tooltip";
 import UserIcon from "../../../components/common/user/UserIcon";