CLI tool
stoatchat/for-legacy-web avatar
stoatchat/for-legacy-web

for-legacy-web: the deprecated Revite client that still serves Stoat users

Legacy web app for Stoat (formerly Revite for Revolt)

960 stars247 forksTypeScriptAGPL-3.0

At a glance

What is it?
for-legacy-web, formerly the Revite web client for Revolt and now the legacy app behind old.stoat.chat, is a Preact and Vite frontend kept alive for a hosted deployment. It is explicitly deprecated, carries an AGPL-3.0 licence, and the README says small fix pull requests are welcome.
Who is it for?
Adopt this codebase only if you specifically need to maintain the legacy Stoat web client at old.stoat.chat or to study how a Preact and Vite chat client was structured, because the project is deprecated and the README points new work at the shared component library and the current client.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 122 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An explicitly deprecated app that still receives traffic

The first line of the README is a deprecation notice, and it is more nuanced than a retirement notice. The project is deprecated, however it still may receive maintenance updates, and pull requests for small fixes are more than welcome.

That combination, deprecated but still maintained opportunistically, describes a legacy application in a specific way. It is not abandoned, so the deployment at old.stoat.chat keeps working, and it is not a going concern, so nobody is adding features to it. The repository description calls it a legacy web app for Stoat, formerly Revite for Revolt, and the homepage points at old.stoat.chat, while the README body still refers to the project as Revite and describes it as the web client for Revolt, live at app.revolt.chat.

Those names are a warning about what you are reading. The application, the repository it came from and the chat platform it talks to have all been renamed at least once, so a stack overflow answer or an issue from two years ago may refer to a codebase with a different name and a different API host.

The last push to the default branch master was on 2026-06-23, and the repository has no GitHub releases, so there is no version history to point at. The package.json carries version 1.0.1, which is an application version rather than a release cadence.

Preact, Vite, and a submodule that other code depends on

The stack is two entries long: Preact and Vite. The repository also carries a .babelrc, a tsconfig.json, a vite.config.ts and a .prettierrc.js, so it is TypeScript on Preact with Babel and ESLint configuration, bundled by Vite.

The structural fact that matters is the submodule. The project contains submodules, and the README asks you to run git submodule init after cloning and recommends git submodule update after pulling from upstream. The external directory holds two of them, components and revolt.js, and they are built before the app itself. The package.json script makes that explicit: build:deps changes into external, then into components, installs and runs yarn build:esm, then into revolt.js, installs and builds. Both are separate projects with their own build steps.

That arrangement explains the pending rewrite section. Components are being migrated to a shared library at revoltchat/components, the styles need to be migrated to the same place, and src/lib still needs to be organised. The components submodule is the old location of the code that is moving to a package both this client and others can depend on.

For an adopter, this is the single most important fact about the codebase. Its component layer is in motion, so touching a component in src/components means colliding with an ongoing migration.

Running the client locally with yarn and Vite

The quick start is five commands, and the recursive clone matters because the submodules have to be present before anything will build:

code
git clone --recursive https://github.com/revoltchat/revite
cd revite
yarn
yarn build:deps
yarn dev

After that the client is reachable at http://local.revolt.chat:3000. Note that the local host name is still the Revolt one, another remnant of the previous naming.

The dev script does more than start Vite. It runs node scripts/setup_assets.js --check before vite, so asset setup is verified rather than assumed. There is a separate yarn pull command that performs the same setup, and a scripts directory at the repository root with setup_assets.js and inject.js.

The build path is longer. yarn build runs yarn, removes the build directory with rimraf, checks the assets, builds the submodule dependencies and then runs vite build. A separate yarn build:highmem exists, which sets NODE_OPTIONS to --max-old-space-size=4096 before building. The Docker image uses the high memory variant, which tells you the plain build can exhaust the default heap on a large project and that this is a known condition rather than a local misconfiguration.

The command list reveals how the project is maintained

The CLI command table in the README is the most informative part of the documentation, because it shows the maintenance workflow of a client that has to keep working.

Beyond dev, build and preview, there are yarn lint to run ESLint, yarn fmt to run Prettier over the source, and yarn typecheck running tsc with noEmit. For serving a built client there are two options: yarn start runs a local sirv server over the dist directory with CORS and single-page fallback, and yarn start:inject runs the inject script first and then serves a dist_injected directory. The injected build is the one the container uses, and it exists because the same image has to be pointed at different API origins.

One command is about localisation rather than code: yarn lint | egrep "no-literals" -B 1 scans for untranslated strings. The ESLint config sets react/jsx-no-literals to warn, which is what that scan picks up. A chat client with a translation system will accumulate hardcoded strings, and this command is the guard against it.

The ESLint configuration also tells you what the code tolerates. The parser is @typescript-eslint/parser and the config extends the preact preset plus the recommended TypeScript rules, with several rules turned off: radix, no-spaced-func, react/no-danger, explicit-module-boundary-types and no-non-null-assertion. react/no-danger being off is worth noting, since that rule exists to flag dangerouslySetInnerHTML.

Deployment is a shell script plus a Docker image

The README documents how a release is deployed. The first requirement is configuration: ensure .env.local points to the API origin, with the example given as https://app.revolt.chat/api. Then the deployment directory is updated and the submodules are refreshed:

bash
cd ~/deployments/revite
git pull
git submodule update

A git status check follows, then the environment is set and the publish script runs:

bash
export REVOLT_SAAS_BRANCH=revite/main
export REMOTE=root@production
scripts/publish.sh

The last step is a manual restart over SSH into a tmux session, which tells you the deployment is a scripted publish followed by a human restarting a long-running process.

The Dockerfile shows the containerised variant, and it is a two-stage build. The builder stage uses node:16-buster, copies the tree, replaces .env with .env.build, installs with a frozen lockfile, builds the submodule dependencies and then runs yarn build:highmem. Two build arguments exist, REVOLT_SAAS and REVOLT_SAAS_BRANCH, so the branch of the SaaS backend can be chosen at image build time. The runtime stage is node:24-alpine with REVOLT_PUBLIC_URL defaulted to https://api.stoat.chat/, it exposes port 5000, and its command is yarn start:inject. The container therefore serves the injected build, which is how one image serves different API origins.

AGPL-3.0 and the cost of touching a deprecated client

The licence is the GNU Affero General Public License v3.0, stated in the README and with a LICENSE file at the repository root. For a frontend client that talks to a chat API over the network, the AGPL obligations attach to the code you distribute, and anyone who offers the modified program as a service is also in scope. I am not a lawyer and this is not legal advice, but the practical consequence is worth stating plainly: if you take this code into a product that is not itself AGPL, that is a conversation to have with whoever owns your compliance process, not something to decide quietly.

The cost side of the decision is the technical debt the README already names. src/components is being migrated to the shared components library, src/styles needs the same migration, and src/lib needs organising. A codebase in that state will produce merge conflicts for you and for anyone else, and there is no versioned release series to fall back on.

There is also no documentation of a rollback path. The repository has no GitHub releases, the README does not describe how to return to an earlier state of the deployment, and the deployment procedure is a manual git pull plus tmux restart rather than a versioned artifact promotion.

What the project does offer is a place to contribute and a place to look. The README points at an issue board, a folder of screenshots, the Revolt project board for feature requests, a testers server invite and a contribution guide for the backend, and the maintainer asks that people who use the project get in touch about their own work. That is the right way to use a deprecated repository: as a reference, and as a source of small fixes when you find one.

Editorial conclusion

Adopt this codebase only if you specifically need to maintain the legacy Stoat web client at old.stoat.chat or to study how a Preact and Vite chat client was structured, because the project is deprecated and the README points new work at the shared component library and the current client. Do not start a new product on it, and do not fork it into a proprietary application without reading the AGPL-3.0 obligations, since the README states the client is licensed under the GNU Affero General Public License v3.0. Verify first that you can still build it, using yarn build:deps to compile the submodule dependencies and yarn build:highmem if the build runs out of memory, and that .env.local still points at the API origin you intend to talk to before you change anything.

Frequently asked questions

Is the for-legacy-web Revite client still maintained?

The README carries a deprecation notice that says the project is deprecated but may still receive maintenance updates, and that pull requests for small fixes are welcome. The last push to the default branch master was on 2026-06-23 and the repository has no GitHub releases.

How do I run the Revite client locally?

Clone the repository recursively with git clone --recursive, then run yarn, yarn build:deps and yarn dev. The client is then reachable at http://local.revolt.chat:3000.

What licence does for-legacy-web use?

The README states that Revite is licensed under the GNU Affero General Public License v3.0, and the repository carries a LICENSE file at its root.

Why does the build run out of memory on this project?

The package.json includes a build:highmem script that sets NODE_OPTIONS to --max-old-space-size=4096 before building, and the Dockerfile uses it. If the normal build fails on memory, use that variant.

How do I point a build at a different API origin?

The README says to ensure .env.local points at the API origin, with https://app.revolt.chat/api given as the example. The container path does the same with the REVOLT_PUBLIC_URL build argument, which defaults to https://api.stoat.chat/, and serves the injected build through yarn start:inject.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. stoatchat/for-legacy-web on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stoatchat-for-legacy-web.svg)](https://hysenlabs.com/projects/stoatchat-for-legacy-web)

Was this useful?