From a9bb39a29a097fa7f16e005ed39f91b6c6fd141f Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 15:45:47 +0100 Subject: [PATCH 01/15] feat: add InstanceContext The purpose of this context is to hold information about a single instance of stoat (information that is currently stored in global configuration) Signed-off-by: Gtoasted --- .../client/components/instance/Instance.ts | 7 ++++ packages/client/components/instance/index.tsx | 25 +++++++++++++ packages/client/src/index.tsx | 35 ++++++++++--------- packages/client/tsconfig.json | 2 ++ 4 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 packages/client/components/instance/Instance.ts create mode 100644 packages/client/components/instance/index.tsx diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts new file mode 100644 index 0000000000..25f0616060 --- /dev/null +++ b/packages/client/components/instance/Instance.ts @@ -0,0 +1,7 @@ +export default class Instance { + readonly apiUrl: string; + + constructor(apiUrl: string) { + this.apiUrl = apiUrl; + } +} diff --git a/packages/client/components/instance/index.tsx b/packages/client/components/instance/index.tsx new file mode 100644 index 0000000000..f2e5c02f98 --- /dev/null +++ b/packages/client/components/instance/index.tsx @@ -0,0 +1,25 @@ +import { CONFIGURATION } from "@revolt/common"; +import { createContext, JSXElement, useContext } from "solid-js"; +import Instance from "./Instance"; + +const instanceContext = createContext(); + +export function InstanceContext(props: { children: JSXElement }) { + return ( + + {props.children} + + ); +} + +export function useInstance() { + const instance = useContext(instanceContext); + + if (!instance) { + throw new Error("useInstance must be called inside InstanceProvider"); + } + + return instance; +} diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx index 28ab542a4d..b81191d1ec 100644 --- a/packages/client/src/index.tsx +++ b/packages/client/src/index.tsx @@ -33,6 +33,7 @@ import { FloatingManager, LoadTheme } from "@revolt/ui"; /* @refresh reload */ import "@revolt/ui/styles"; +import { InstanceContext } from "@revolt/instance"; import AuthPage from "./Auth"; import Interface from "./Interface"; import "./index.css"; @@ -117,22 +118,24 @@ function MountContext(props: { children?: JSX.Element }) { const client = new QueryClient(); return ( - - - - - - - {props.children} - - - - - - - - - + + + + + + + + {props.children} + + + + + + + + + + ); } diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json index c42a88297f..75ee401db1 100644 --- a/packages/client/tsconfig.json +++ b/packages/client/tsconfig.json @@ -29,6 +29,8 @@ "@revolt/client/*": ["components/client/*"], "@revolt/common": ["components/common"], "@revolt/common/*": ["components/common/*"], + "@revolt/instance": ["components/instance"], + "@revolt/instance/*": ["components/instance/*"], "@revolt/i18n": ["components/i18n"], "@revolt/i18n/*": ["components/i18n/*"], "@revolt/keybinds": ["components/keybinds"], From 81b4faf78aa6420fbbb02a2c655d9b8e22a97981 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 16:32:34 +0100 Subject: [PATCH 02/15] refactor: use Instance.apiUrl instead of CONFIGURATION.DEFAULT_API_URL Signed-off-by: Gtoasted --- .../settings/channel/webhooks/ViewWebhook.tsx | 4 +++- packages/client/components/client/Controller.ts | 13 ++++++++++--- packages/client/components/client/index.tsx | 4 +++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx b/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx index 1210aeacf3..83ff8316f9 100644 --- a/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx +++ b/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx @@ -19,6 +19,7 @@ import { import MdContentCopy from "@material-design-icons/svg/outlined/content_copy.svg?component-solid"; import MdDelete from "@material-design-icons/svg/outlined/delete.svg?component-solid"; +import { useInstance } from "@revolt/instance"; import { useSettingsNavigation } from "../../Settings"; /** @@ -29,6 +30,7 @@ export function ViewWebhook(props: { webhook: ChannelWebhook }) { const client = useClient(); const { showError } = useModals(); const { navigate } = useSettingsNavigation(); + const instance = useInstance(); /* eslint-disable solid/reactivity */ const editGroup = createFormGroup({ @@ -120,7 +122,7 @@ export function ViewWebhook(props: { webhook: ChannelWebhook }) { icon={} onClick={() => navigator.clipboard.writeText( - `${CONFIGURATION.DEFAULT_API_URL}/webhooks/${props.webhook.id}/${props.webhook.token}`, + `${instance.apiUrl}/webhooks/${props.webhook.id}/${props.webhook.token}`, ) } > diff --git a/packages/client/components/client/Controller.ts b/packages/client/components/client/Controller.ts index 7180ba04ba..ca2855f9d2 100644 --- a/packages/client/components/client/Controller.ts +++ b/packages/client/components/client/Controller.ts @@ -8,6 +8,7 @@ import { CONFIGURATION } from "@revolt/common"; import { ModalControllerExtended } from "@revolt/modal"; import type { State as ApplicationState } from "@revolt/state"; import type { Session } from "@revolt/state/stores/Auth"; +import Instance from "../instance/Instance"; export enum State { Ready = "Ready", @@ -126,7 +127,7 @@ class Lifecycle { } this.client = new Client({ - baseURL: CONFIGURATION.DEFAULT_API_URL, + baseURL: this.#controller.instance.apiUrl, autoReconnect: false, syncUnreads: true, debug: import.meta.env.DEV, @@ -445,13 +446,19 @@ export default class ClientController { */ readonly state: ApplicationState; + /** + * Reference to the instance the client connects to + */ + readonly instance: Instance; + /** * Construct new client controller */ - constructor(state: ApplicationState) { + constructor(state: ApplicationState, instance: Instance) { this.state = state; + this.instance = instance; this.api = new API.API({ - baseURL: CONFIGURATION.DEFAULT_API_URL, + baseURL: instance.apiUrl, }); this.lifecycle = new Lifecycle(this); diff --git a/packages/client/components/client/index.tsx b/packages/client/components/client/index.tsx index 47741e438d..2e6ce25231 100644 --- a/packages/client/components/client/index.tsx +++ b/packages/client/components/client/index.tsx @@ -15,6 +15,7 @@ import { State } from "@revolt/state"; import { State as LifecycleState } from "./Controller"; +import { useInstance } from "@revolt/instance"; import { CHANGELOG_MODAL_CONST } from "@revolt/modal/modals/Changelog"; import ClientController from "./Controller"; @@ -27,9 +28,10 @@ const clientContext = createContext(null! as ClientController); */ export function ClientContext(props: { state: State; children: JSXElement }) { const { openModal } = useModals(); + const instance = useInstance(); // eslint-disable-next-line solid/reactivity - const controller = new ClientController(props.state); + const controller = new ClientController(props.state, instance); onCleanup(() => controller.dispose()); createEffect(() => { From c090a905a47c8e12b68b9f76dfc0505bbf702574 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 16:37:59 +0100 Subject: [PATCH 03/15] refactor: use Instance.wsUrl instead of CONFIGURATION.DEFAULT_WS_URL Signed-off-by: Gtoasted --- packages/client/components/client/Controller.ts | 2 +- packages/client/components/instance/Instance.ts | 4 +++- packages/client/components/instance/index.tsx | 7 ++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/client/components/client/Controller.ts b/packages/client/components/client/Controller.ts index ca2855f9d2..339d4e2ad6 100644 --- a/packages/client/components/client/Controller.ts +++ b/packages/client/components/client/Controller.ts @@ -159,7 +159,7 @@ class Lifecycle { }, }, vapid: String(), - ws: CONFIGURATION.DEFAULT_WS_URL, + ws: this.#controller.instance.wsUrl, }; this.client.events.on("state", this.onState); diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts index 25f0616060..00f9c2dfb7 100644 --- a/packages/client/components/instance/Instance.ts +++ b/packages/client/components/instance/Instance.ts @@ -1,7 +1,9 @@ export default class Instance { readonly apiUrl: string; + readonly wsUrl: string; - constructor(apiUrl: string) { + constructor(apiUrl: string, wsUrl: string) { this.apiUrl = apiUrl; + this.wsUrl = wsUrl; } } diff --git a/packages/client/components/instance/index.tsx b/packages/client/components/instance/index.tsx index f2e5c02f98..8dd5e2d80d 100644 --- a/packages/client/components/instance/index.tsx +++ b/packages/client/components/instance/index.tsx @@ -7,7 +7,12 @@ const instanceContext = createContext(); export function InstanceContext(props: { children: JSXElement }) { return ( {props.children} From e44fff83079cec1623898828998fee19a673ec29 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 16:47:14 +0100 Subject: [PATCH 04/15] refactor: use Instance.mediaUrl instead of CONFIGURATION.DEFAULT_MEDIA_URL Signed-off-by: Gtoasted --- .../app/interface/settings/channel/Overview.tsx | 5 +++-- .../interface/settings/channel/webhooks/ViewWebhook.tsx | 3 +-- .../app/interface/settings/server/Overview.tsx | 7 ++++--- .../app/interface/settings/server/emojis/EmojiList.tsx | 4 +++- .../settings/user/profile/UserProfileEditor.tsx | 9 +++++---- packages/client/components/client/Controller.ts | 2 +- packages/client/components/instance/Instance.ts | 4 +++- packages/client/components/instance/index.tsx | 1 + .../client/components/modal/modals/ServerIdentity.tsx | 5 +++-- 9 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/client/components/app/interface/settings/channel/Overview.tsx b/packages/client/components/app/interface/settings/channel/Overview.tsx index 97f42c1f0c..1427847f49 100644 --- a/packages/client/components/app/interface/settings/channel/Overview.tsx +++ b/packages/client/components/app/interface/settings/channel/Overview.tsx @@ -5,10 +5,10 @@ import { Trans, useLingui } from "@lingui-solid/solid/macro"; import type { API } from "stoat.js"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; import { useModals } from "@revolt/modal"; import { Button, CircularProgress, Column, Form2, Row, Text } from "@revolt/ui"; +import { useInstance } from "@revolt/instance"; import { ChannelSettingsProps } from "../ChannelSettings"; /** @@ -18,6 +18,7 @@ export default function ChannelOverview(props: ChannelSettingsProps) { const { t } = useLingui(); const client = useClient(); const { openModal } = useModals(); + const instance = useInstance(); /* eslint-disable solid/reactivity */ // we want to take the initial value only @@ -64,7 +65,7 @@ export default function ChannelOverview(props: ChannelSettingsProps) { const [key, value] = client().authenticationHeader; const data: { id: string } = await fetch( - `${CONFIGURATION.DEFAULT_MEDIA_URL}/icons`, + `${instance.mediaUrl}/icons`, { method: "POST", body, diff --git a/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx b/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx index 83ff8316f9..ae41dcb276 100644 --- a/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx +++ b/packages/client/components/app/interface/settings/channel/webhooks/ViewWebhook.tsx @@ -6,7 +6,6 @@ import { useMutation } from "@tanstack/solid-query"; import { API, ChannelWebhook } from "stoat.js"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; import { useModals } from "@revolt/modal"; import { CategoryButton, @@ -65,7 +64,7 @@ export function ViewWebhook(props: { webhook: ChannelWebhook }) { const [key, value] = client().authenticationHeader; const data: { id: string } = await fetch( - `${CONFIGURATION.DEFAULT_MEDIA_URL}/avatars`, + `${instance.mediaUrl}/avatars`, { method: "POST", body, diff --git a/packages/client/components/app/interface/settings/server/Overview.tsx b/packages/client/components/app/interface/settings/server/Overview.tsx index edd0c7adca..fc37740df9 100644 --- a/packages/client/components/app/interface/settings/server/Overview.tsx +++ b/packages/client/components/app/interface/settings/server/Overview.tsx @@ -5,7 +5,6 @@ import { Trans, useLingui } from "@lingui-solid/solid/macro"; import type { API } from "stoat.js"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; import { CircularProgress, Column, @@ -15,6 +14,7 @@ import { Text, } from "@revolt/ui"; +import { useInstance } from "@revolt/instance"; import { ServerSettingsProps } from "../ServerSettings"; /** @@ -23,6 +23,7 @@ import { ServerSettingsProps } from "../ServerSettings"; export default function ServerOverview(props: ServerSettingsProps) { const { t } = useLingui(); const client = useClient(); + const instance = useInstance(); /* eslint-disable solid/reactivity */ const editGroup = createFormGroup({ @@ -144,7 +145,7 @@ export default function ServerOverview(props: ServerSettingsProps) { changes.icon = await client().uploadFile( "icons", editGroup.controls.icon.value[0], - CONFIGURATION.DEFAULT_MEDIA_URL, + instance.mediaUrl, ); } } @@ -156,7 +157,7 @@ export default function ServerOverview(props: ServerSettingsProps) { changes.banner = await client().uploadFile( "banners", editGroup.controls.banner.value[0], - CONFIGURATION.DEFAULT_MEDIA_URL, + instance.mediaUrl, ); } } diff --git a/packages/client/components/app/interface/settings/server/emojis/EmojiList.tsx b/packages/client/components/app/interface/settings/server/emojis/EmojiList.tsx index ecc8fd6cf6..1b91044af0 100644 --- a/packages/client/components/app/interface/settings/server/emojis/EmojiList.tsx +++ b/packages/client/components/app/interface/settings/server/emojis/EmojiList.tsx @@ -8,6 +8,7 @@ import { css } from "styled-system/css"; import { useClient } from "@revolt/client"; import { CONFIGURATION } from "@revolt/common"; import { useError } from "@revolt/i18n"; +import { useInstance } from "@revolt/instance"; import { useModals } from "@revolt/modal"; import { Avatar, @@ -27,6 +28,7 @@ export function EmojiList(props: { server: Server }) { const { t } = useLingui(); const client = useClient(); const { openModal } = useModals(); + const instance = useInstance(); function isDisabled() { return props.server.emojis.length >= CONFIGURATION.MAX_EMOJI; @@ -50,7 +52,7 @@ export function EmojiList(props: { server: Server }) { const [key, value] = client().authenticationHeader; const data: { id: string } = await fetch( - `${CONFIGURATION.DEFAULT_MEDIA_URL}/emojis`, + `${instance.mediaUrl}/emojis`, { method: "POST", body, diff --git a/packages/client/components/app/interface/settings/user/profile/UserProfileEditor.tsx b/packages/client/components/app/interface/settings/user/profile/UserProfileEditor.tsx index d105e35baf..e805621f67 100644 --- a/packages/client/components/app/interface/settings/user/profile/UserProfileEditor.tsx +++ b/packages/client/components/app/interface/settings/user/profile/UserProfileEditor.tsx @@ -6,7 +6,6 @@ import { useQuery, useQueryClient } from "@tanstack/solid-query"; import { API, User } from "stoat.js"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; import { CategoryButton, CircularProgress, @@ -18,6 +17,7 @@ import { import MdBadge from "@material-design-icons/svg/filled/badge.svg?component-solid"; +import { useInstance } from "@revolt/instance"; import { useSettingsNavigation } from "../../Settings"; interface Props { @@ -28,6 +28,7 @@ export function UserProfileEditor(props: Props) { const { t } = useLingui(); const client = useClient(); const queryClient = useQueryClient(); + const instance = useInstance(); const profile = useQuery(() => ({ queryKey: ["profile", props.user.id], @@ -102,7 +103,7 @@ export function UserProfileEditor(props: Props) { changes.avatar = await client().uploadFile( "avatars", editGroup.controls.avatar.value[0], - CONFIGURATION.DEFAULT_MEDIA_URL, + instance.mediaUrl, ); } } @@ -126,10 +127,10 @@ export function UserProfileEditor(props: Props) { changes.profile.background = await client().uploadFile( "backgrounds", editGroup.controls.banner.value[0], - CONFIGURATION.DEFAULT_MEDIA_URL, + instance.mediaUrl, ); - newBannerUrl = `${CONFIGURATION.DEFAULT_MEDIA_URL}/backgrounds/${changes.profile.background}`; + newBannerUrl = `${instance.mediaUrl}/backgrounds/${changes.profile.background}`; } else { newBannerUrl = editGroup.controls.banner.value; } diff --git a/packages/client/components/client/Controller.ts b/packages/client/components/client/Controller.ts index 339d4e2ad6..ad4be5b7ff 100644 --- a/packages/client/components/client/Controller.ts +++ b/packages/client/components/client/Controller.ts @@ -144,7 +144,7 @@ class Lifecycle { features: { autumn: { enabled: true, - url: CONFIGURATION.DEFAULT_MEDIA_URL, + url: this.#controller.instance.mediaUrl, }, january: { enabled: true, diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts index 00f9c2dfb7..b2a57b4060 100644 --- a/packages/client/components/instance/Instance.ts +++ b/packages/client/components/instance/Instance.ts @@ -1,9 +1,11 @@ export default class Instance { readonly apiUrl: string; readonly wsUrl: string; + readonly mediaUrl: string; - constructor(apiUrl: string, wsUrl: string) { + constructor(apiUrl: string, wsUrl: string, mediaUrl: string) { this.apiUrl = apiUrl; this.wsUrl = wsUrl; + this.mediaUrl = mediaUrl; } } diff --git a/packages/client/components/instance/index.tsx b/packages/client/components/instance/index.tsx index 8dd5e2d80d..db03f9ddd8 100644 --- a/packages/client/components/instance/index.tsx +++ b/packages/client/components/instance/index.tsx @@ -11,6 +11,7 @@ export function InstanceContext(props: { children: JSXElement }) { new Instance( CONFIGURATION.DEFAULT_API_URL, CONFIGURATION.DEFAULT_WS_URL, + CONFIGURATION.DEFAULT_MEDIA_URL, ) } > diff --git a/packages/client/components/modal/modals/ServerIdentity.tsx b/packages/client/components/modal/modals/ServerIdentity.tsx index dcc197c9cc..18306dfc89 100644 --- a/packages/client/components/modal/modals/ServerIdentity.tsx +++ b/packages/client/components/modal/modals/ServerIdentity.tsx @@ -4,9 +4,9 @@ import { Trans, useLingui } from "@lingui-solid/solid/macro"; import { API } from "stoat.js"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; import { Column, Dialog, DialogProps, Form2 } from "@revolt/ui"; +import { useInstance } from "@revolt/instance"; import { useModals } from ".."; import { Modals } from "../types"; @@ -19,6 +19,7 @@ export function ServerIdentityModal( const { t } = useLingui(); const client = useClient(); const { showError } = useModals(); + const instance = useInstance(); /* eslint-disable solid/reactivity */ const group = createFormGroup({ @@ -51,7 +52,7 @@ export function ServerIdentityModal( changes.avatar = await client().uploadFile( "avatars", group.controls.avatar.value[0], - CONFIGURATION.DEFAULT_MEDIA_URL, + instance.mediaUrl, ); } } From c3346292bfe6438416c96a6e85b48ea6883868e1 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 16:52:40 +0100 Subject: [PATCH 05/15] refactor: use Instance.proxyUrl instead of CONFIGURATION.DEFAULT_PROXY_URL Signed-off-by: Gtoasted --- packages/client/components/client/Controller.ts | 3 +-- packages/client/components/instance/Instance.ts | 9 ++++++++- packages/client/components/instance/index.tsx | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/client/components/client/Controller.ts b/packages/client/components/client/Controller.ts index ad4be5b7ff..925a526a33 100644 --- a/packages/client/components/client/Controller.ts +++ b/packages/client/components/client/Controller.ts @@ -4,7 +4,6 @@ import { detect } from "detect-browser"; import { API, Client, ConnectionState } from "stoat.js"; import { ProtocolV1 } from "stoat.js/lib/events/v1"; -import { CONFIGURATION } from "@revolt/common"; import { ModalControllerExtended } from "@revolt/modal"; import type { State as ApplicationState } from "@revolt/state"; import type { Session } from "@revolt/state/stores/Auth"; @@ -148,7 +147,7 @@ class Lifecycle { }, january: { enabled: true, - url: CONFIGURATION.DEFAULT_PROXY_URL, + url: this.#controller.instance.proxyUrl, }, captcha: {} as never, email: true, diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts index b2a57b4060..4e7e228549 100644 --- a/packages/client/components/instance/Instance.ts +++ b/packages/client/components/instance/Instance.ts @@ -2,10 +2,17 @@ export default class Instance { readonly apiUrl: string; readonly wsUrl: string; readonly mediaUrl: string; + readonly proxyUrl: string; - constructor(apiUrl: string, wsUrl: string, mediaUrl: string) { + constructor( + apiUrl: string, + wsUrl: string, + mediaUrl: string, + proxyUrl: string, + ) { this.apiUrl = apiUrl; this.wsUrl = wsUrl; this.mediaUrl = mediaUrl; + this.proxyUrl = proxyUrl; } } diff --git a/packages/client/components/instance/index.tsx b/packages/client/components/instance/index.tsx index db03f9ddd8..04c1256065 100644 --- a/packages/client/components/instance/index.tsx +++ b/packages/client/components/instance/index.tsx @@ -12,6 +12,7 @@ export function InstanceContext(props: { children: JSXElement }) { CONFIGURATION.DEFAULT_API_URL, CONFIGURATION.DEFAULT_WS_URL, CONFIGURATION.DEFAULT_MEDIA_URL, + CONFIGURATION.DEFAULT_PROXY_URL, ) } > From 86b02121505cff3d7356619b35fd12d2bac6e391 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 16:59:28 +0100 Subject: [PATCH 06/15] refactor: use Instance.gifboxUrl instead of CONFIGURATION.DEFAULT_GIFBOX_URL Signed-off-by: Gtoasted --- packages/client/components/instance/Instance.ts | 3 +++ packages/client/components/instance/index.tsx | 1 + .../features/messaging/composition/picker/GifPicker.tsx | 9 ++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts index 4e7e228549..ae8d910e75 100644 --- a/packages/client/components/instance/Instance.ts +++ b/packages/client/components/instance/Instance.ts @@ -3,16 +3,19 @@ export default class Instance { readonly wsUrl: string; readonly mediaUrl: string; readonly proxyUrl: string; + readonly gifboxUrl: string; constructor( apiUrl: string, wsUrl: string, mediaUrl: string, proxyUrl: string, + gifboxUrl: string, ) { this.apiUrl = apiUrl; this.wsUrl = wsUrl; this.mediaUrl = mediaUrl; this.proxyUrl = proxyUrl; + this.gifboxUrl = gifboxUrl; } } diff --git a/packages/client/components/instance/index.tsx b/packages/client/components/instance/index.tsx index 04c1256065..f3a1edac0f 100644 --- a/packages/client/components/instance/index.tsx +++ b/packages/client/components/instance/index.tsx @@ -13,6 +13,7 @@ export function InstanceContext(props: { children: JSXElement }) { CONFIGURATION.DEFAULT_WS_URL, CONFIGURATION.DEFAULT_MEDIA_URL, CONFIGURATION.DEFAULT_PROXY_URL, + CONFIGURATION.DEFAULT_GIFBOX_URL, ) } > diff --git a/packages/client/components/ui/components/features/messaging/composition/picker/GifPicker.tsx b/packages/client/components/ui/components/features/messaging/composition/picker/GifPicker.tsx index 5c79cc1a77..32b0412f11 100644 --- a/packages/client/components/ui/components/features/messaging/composition/picker/GifPicker.tsx +++ b/packages/client/components/ui/components/features/messaging/composition/picker/GifPicker.tsx @@ -15,6 +15,7 @@ import { styled } from "styled-system/jsx"; import { useClient } from "@revolt/client"; import env from "@revolt/common/lib/env"; +import { useInstance } from "@revolt/instance"; import { CircularProgress, TextField, @@ -96,13 +97,14 @@ function Categories() { let targetElement!: HTMLDivElement; const client = useClient(); + const instance = useInstance(); const trendingCategories = useQuery(() => ({ queryKey: ["trendingGifCategories"], queryFn: () => { const [authHeader, authHeaderValue] = client()!.authenticationHeader; - return fetch(`${env.DEFAULT_GIFBOX_URL}/categories?locale=en_US`, { + return fetch(`${instance.gifboxUrl}/categories?locale=en_US`, { headers: { [authHeader]: authHeaderValue, }, @@ -117,7 +119,7 @@ function Categories() { queryFn: () => { const [authHeader, authHeaderValue] = client()!.authenticationHeader; - return fetch(`${env.DEFAULT_GIFBOX_URL}/trending?locale=en_US&limit=1`, { + return fetch(`${instance.gifboxUrl}/trending?locale=en_US&limit=1`, { headers: { [authHeader]: authHeaderValue, }, @@ -214,6 +216,7 @@ function GifSearch(props: { query: string }) { let targetElement!: HTMLDivElement; const client = useClient(); + const instance = useInstance(); const search = useQuery(() => ({ queryKey: ["gifs", props.query], @@ -221,7 +224,7 @@ function GifSearch(props: { query: string }) { const [authHeader, authHeaderValue] = client()!.authenticationHeader; return fetch( - `${env.DEFAULT_GIFBOX_URL}/` + + `${instance.gifboxUrl}/` + (props.query === "trending" ? `trending?locale=en_US` : `search?locale=en_US&query=${encodeURIComponent(props.query)}`), From 2c711aed6a875bbf4065625c60dda007d0e9d2b2 Mon Sep 17 00:00:00 2001 From: Gtoasted Date: Thu, 5 Mar 2026 19:17:03 +0100 Subject: [PATCH 07/15] refactor: use Instance.isStoat instead of CONFIGURATION.IS_STOAT Signed-off-by: Gtoasted --- .../components/app/interface/settings/user/Feedback.tsx | 5 +++-- packages/client/components/instance/Instance.ts | 9 +++++++++ packages/client/components/modal/modals/CreateInvite.tsx | 4 +++- packages/client/src/interface/Home.tsx | 6 ++++-- .../src/interface/navigation/servers/ServerList.tsx | 4 +++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/client/components/app/interface/settings/user/Feedback.tsx b/packages/client/components/app/interface/settings/user/Feedback.tsx index 766a23bafc..5a4784a847 100644 --- a/packages/client/components/app/interface/settings/user/Feedback.tsx +++ b/packages/client/components/app/interface/settings/user/Feedback.tsx @@ -13,7 +13,7 @@ import MdBugReport from "@material-design-icons/svg/outlined/bug_report.svg?comp import MdFormatListNumbered from "@material-design-icons/svg/outlined/format_list_numbered.svg?component-solid"; import MdStar from "@material-design-icons/svg/outlined/star_outline.svg?component-solid"; import { useClient } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; +import { useInstance } from "@revolt/instance"; import { useModals } from "@revolt/modal"; import { useNavigate } from "@solidjs/router"; import { Match, Switch } from "solid-js"; @@ -26,8 +26,9 @@ export function Feedback() { const { openModal, pop } = useModals(); const navigate = useNavigate(); const client = useClient(); + const instance = useInstance(); - const showLoungeButton = CONFIGURATION.IS_STOAT; + const showLoungeButton = instance.isStoat; const isInLounge = client()!.servers.get("01F7ZSBSFHQ8TA81725KQCSDDP") !== undefined; diff --git a/packages/client/components/instance/Instance.ts b/packages/client/components/instance/Instance.ts index ae8d910e75..5d1dc5e1c9 100644 --- a/packages/client/components/instance/Instance.ts +++ b/packages/client/components/instance/Instance.ts @@ -1,4 +1,5 @@ export default class Instance { + readonly isStoat: boolean; readonly apiUrl: string; readonly wsUrl: string; readonly mediaUrl: string; @@ -12,6 +13,14 @@ export default class Instance { proxyUrl: string, gifboxUrl: string, ) { + this.isStoat = [ + // historically... + "https://api.revolt.chat", + "https://beta.revolt.chat/api", + "https://revolt.chat/api", + // ... and now: + "https://stoat.chat/api", + ].includes(apiUrl); this.apiUrl = apiUrl; this.wsUrl = wsUrl; this.mediaUrl = mediaUrl; diff --git a/packages/client/components/modal/modals/CreateInvite.tsx b/packages/client/components/modal/modals/CreateInvite.tsx index 6bc16e495b..862a2de482 100644 --- a/packages/client/components/modal/modals/CreateInvite.tsx +++ b/packages/client/components/modal/modals/CreateInvite.tsx @@ -9,6 +9,7 @@ import { Dialog, DialogProps } from "@revolt/ui"; import { useModals } from ".."; import { Modals } from "../types"; +import { useInstance } from "@revolt/instance"; /** * Code block which displays invite @@ -36,6 +37,7 @@ export function CreateInviteModal( ) { const { showError } = useModals(); const [link, setLink] = createSignal("..."); + const instance = useInstance(); const fetchInvite = useMutation(() => ({ mutationFn: () => @@ -43,7 +45,7 @@ export function CreateInviteModal( .createInvite() .then(({ _id }) => setLink( - CONFIGURATION.IS_STOAT + instance.isStoat ? `https://stt.gg/${_id}` : `${window.location.protocol}//${window.location.host}/invite/${_id}`, ), diff --git a/packages/client/src/interface/Home.tsx b/packages/client/src/interface/Home.tsx index 4801b4bf35..6f6470c711 100644 --- a/packages/client/src/interface/Home.tsx +++ b/packages/client/src/interface/Home.tsx @@ -7,6 +7,7 @@ import { styled } from "styled-system/jsx"; import { IS_DEV, useClient } from "@revolt/client"; import { CONFIGURATION } from "@revolt/common"; +import { useInstance } from "@revolt/instance"; import { useModals } from "@revolt/modal"; import { useNavigate } from "@revolt/routing"; import { @@ -94,9 +95,10 @@ export function HomePage() { const { openModal } = useModals(); const navigate = useNavigate(); const client = useClient(); + const instance = useInstance(); // check if we're stoat.chat; if so, check if the user is in the Lounge - const showLoungeButton = CONFIGURATION.IS_STOAT; + const showLoungeButton = instance.isStoat; const isInLounge = client()!.servers.get("01F7ZSBSFHQ8TA81725KQCSDDP") !== undefined; @@ -189,7 +191,7 @@ export function HomePage() { - + navigate("/discover")} description={ diff --git a/packages/client/src/interface/navigation/servers/ServerList.tsx b/packages/client/src/interface/navigation/servers/ServerList.tsx index c76b803815..64dff1a380 100644 --- a/packages/client/src/interface/navigation/servers/ServerList.tsx +++ b/packages/client/src/interface/navigation/servers/ServerList.tsx @@ -23,6 +23,7 @@ import { Draggable } from "../../../../components/ui/components/utils/Draggable" import { Symbol } from "@revolt/ui/components/utils/Symbol"; import { UserMenu } from "./UserMenu"; +import { useInstance } from "@revolt/instance"; interface Props { /** @@ -70,6 +71,7 @@ export const ServerList = (props: Props) => { const client = useClient(); const navigate = useNavigate(); const { openModal } = useModals(); + const instance = useInstance(); const navigateServer = (byOffset: number) => { const serverId = props.selectedServer(); @@ -303,7 +305,7 @@ export const ServerList = (props: Props) => { } /> - + Date: Thu, 5 Mar 2026 19:22:44 +0100 Subject: [PATCH 08/15] refactor: use Instance.hcaptcha_sitekey instead of CONFIGURATION.HCAPTCHA_SITEKEY Signed-off-by: Gtoasted --- packages/client/components/auth/src/flows/FlowCreate.tsx | 5 +++-- packages/client/components/auth/src/flows/FlowResend.tsx | 5 +++-- packages/client/components/auth/src/flows/FlowReset.tsx | 4 +++- packages/client/components/instance/Instance.ts | 3 +++ packages/client/components/instance/index.tsx | 1 + 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/client/components/auth/src/flows/FlowCreate.tsx b/packages/client/components/auth/src/flows/FlowCreate.tsx index 7e9fc4a66e..1dd7b7cc13 100644 --- a/packages/client/components/auth/src/flows/FlowCreate.tsx +++ b/packages/client/components/auth/src/flows/FlowCreate.tsx @@ -1,6 +1,6 @@ import { Trans } from "@lingui-solid/solid/macro"; -import { CONFIGURATION } from "@revolt/common"; +import { useInstance } from "@revolt/instance"; import { useNavigate } from "@revolt/routing"; import { Button, Row, iconSize } from "@revolt/ui"; @@ -18,6 +18,7 @@ import { Fields, Form } from "./Form"; export default function FlowCreate() { const api = useApi(); const navigate = useNavigate(); + const instance = useInstance(); /** * Create an account @@ -48,7 +49,7 @@ export default function FlowCreate() { Create an account} emoji="wave"> Hello! -
+ diff --git a/packages/client/components/auth/src/flows/FlowResend.tsx b/packages/client/components/auth/src/flows/FlowResend.tsx index 6c826cdb30..1c591a68e0 100644 --- a/packages/client/components/auth/src/flows/FlowResend.tsx +++ b/packages/client/components/auth/src/flows/FlowResend.tsx @@ -1,7 +1,7 @@ import { Trans } from "@lingui-solid/solid/macro"; import { useApi } from "@revolt/client"; -import { CONFIGURATION } from "@revolt/common"; +import { useInstance } from "@revolt/instance"; import { useNavigate } from "@revolt/routing"; import { Button } from "@revolt/ui"; @@ -15,6 +15,7 @@ import { Fields, Form } from "./Form"; export default function FlowResend() { const api = useApi(); const navigate = useNavigate(); + const instance = useInstance(); /** * Resend email verification @@ -38,7 +39,7 @@ export default function FlowResend() { Resend verification - +