diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD
index fb702a2089..935d4a2ab1 100644
--- a/CONTRIBUTING.MD
+++ b/CONTRIBUTING.MD
@@ -3,8 +3,8 @@ Welcome to Spacebar, if you've made it here, I'm guessing you're looking to cont
A good place to start would be over at the issues tab, though https://docs.spacebar.chat/contributing/server/missingroute/
may also be a good indicator for things that are remaining.
-If you find yourself working on something, or want to discuss particular issues, feel free to drop by our developers guild (
-
+If you find yourself working on something, or want to discuss particular issues, feel free to drop by our developers guild (
+
)
Keep in mind that we do, under no circumstances, accept AI-generated, AI-assisted, or otherwise machine-generated contributions, for legal reasons.
diff --git a/README.md b/README.md
index 357cfd3bfe..14fab4719c 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,8 @@
-
-
+
+
@@ -48,4 +48,4 @@ And with documentation on how to set up your own server [here](https://docs.spac
You _should_ be able to use any client designed for Discord.com to connect to a Spacebar instance.
However, some incompatibilities still exist between Spacebar and Discord. For this reason, not every client will connect.
We recommend using [Fermo](https://fermo.sovr.top/login?instance=spacebar.chat) as a solid starting point on your adventure in the SpaceBar!
-You can explore other clients with the [Spacebar Explorer](https://spacebar-explorer.sovr.top/clients).
+You can explore other clients with the [Spacebar Explorer](https://sbar.top/clients).
diff --git a/src/gateway/util/Send.ts b/src/gateway/util/Send.ts
index f857a40033..4d6185943a 100644
--- a/src/gateway/util/Send.ts
+++ b/src/gateway/util/Send.ts
@@ -20,7 +20,7 @@ import { Payload, WebSocket } from "@spacebar/gateway";
import fs from "node:fs/promises";
import path from "node:path";
-import { JSONReplacer } from "@spacebar/util";
+import { JSONReplacer, cleanCircularRefs } from "@spacebar/util";
import * as erlpack from "harmony-erlpack";
// don't care
@@ -54,10 +54,9 @@ export async function Send(socket: WebSocket, data: Payload) {
// Erlpack doesn't like Date objects, encodes them as {}
data = recurseJsonReplace(data);
buffer = Buffer.from(erlpack.pack(data));
- }
- // TODO: encode circular object
- else if (socket.encoding === "json") buffer = JSON.stringify(data, JSONReplacer);
- else return;
+ } else if (socket.encoding === "json") {
+ buffer = JSON.stringify(cleanCircularRefs(data), JSONReplacer);
+ } else return;
// TODO: compression
if (socket.compress === "zlib-stream") {
diff --git a/src/util/util/JSON.ts b/src/util/util/JSON.ts
index e716f7d4a4..e2e15ddd95 100644
--- a/src/util/util/JSON.ts
+++ b/src/util/util/JSON.ts
@@ -36,3 +36,28 @@ export function JSONReplacer(this: { [key: string]: unknown }, key: string, valu
return value;
}
+
+/**
+ * Walk an object tree and null out circular references in-place,
+ * while preserving shared (non-circular) references.
+ */
+export function cleanCircularRefs(data: T): T {
+ const ancestors = new Set