Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: use Deno tooling #111

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
BREAKING CHANGE: remove solid.js dependency and redo collection inter…
…face
williamhorning committed Mar 14, 2025

Verified

This commit was signed with the committer’s verified signature.
vinnymeller Vinny Meller
commit 02a541339d22c836adf7ed27a51d000817dfc149
3 changes: 1 addition & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["solid", "spellcheck"],
"plugins": ["spellcheck"],
"extends": [
"eslint:recommended",
"plugin:solid/typescript",
"plugin:@typescript-eslint/recommended",
"prettier"
],
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
"editor.formatOnSave": true,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -26,8 +26,6 @@
"description": "Library for interacting with the Revolt API.",
"packageManager": "[email protected]",
"dependencies": {
"@solid-primitives/map": "^0.4.11",
"@solid-primitives/set": "^0.4.11",
"eventemitter3": "^5.0.1",
"isomorphic-ws": "^5.0.0",
"long": "^5.2.3",
@@ -46,12 +44,11 @@
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-solid": "^0.12.1",
"eslint-plugin-spellcheck": "^0.0.20",
"prettier": "^2.8.8",
"tsc-watch": "^6.0.4",
"typed-emitter": "^2.1.0",
"typedoc": "^0.25.1",
"typescript": "^5.4.2"
}
}
}
41 changes: 16 additions & 25 deletions src/Client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Accessor, Setter, batch, createSignal } from "solid-js";

import EventEmitter from "eventemitter3";
import type { DataLogin, Error, RevoltConfig } from "revolt-api";
import type { DataLogin, RevoltConfig } from "revolt-api";
import { API, Role } from "revolt-api";

import {
@@ -180,11 +178,9 @@ export class Client extends EventEmitter<Events> {
#session: Session | undefined;
user: User | undefined;

readonly ready: Accessor<boolean>;
#setReady: Setter<boolean>;
ready = false;
connectionFailureCount = 0;

readonly connectionFailureCount: Accessor<number>;
#setConnectionFailureCount: Setter<number>;
#reconnectTimeout: number | undefined;

/**
@@ -225,14 +221,6 @@ export class Client extends EventEmitter<Events> {
baseURL: this.options.baseURL,
});

const [ready, setReady] = createSignal(false);
this.ready = ready;
this.#setReady = setReady;

const [connectionFailureCount, setConnectionFailureCount] = createSignal(0);
this.connectionFailureCount = connectionFailureCount;
this.#setConnectionFailureCount = setConnectionFailureCount;

this.account = new AccountCollection(this);
this.bots = new BotCollection(this);
this.channels = new ChannelCollection(this);
@@ -250,11 +238,9 @@ export class Client extends EventEmitter<Events> {
this.events.on("state", (state) => {
switch (state) {
case ConnectionState.Connected:
batch(() => {
this.servers.forEach((server) => server.resetSyncStatus());
this.#setConnectionFailureCount(0);
this.emit("connected");
});
this.servers.forEach((server) => server.resetSyncStatus());
this.connectionFailureCount = 0;
this.emit("connected");
break;
case ConnectionState.Connecting:
this.emit("connecting");
@@ -264,18 +250,23 @@ export class Client extends EventEmitter<Events> {
if (this.options.autoReconnect) {
this.#reconnectTimeout = setTimeout(
() => this.connect(),
this.options.retryDelayFunction(this.connectionFailureCount()) *
1e3
this.options.retryDelayFunction(this.connectionFailureCount) * 1e3
) as never;

this.#setConnectionFailureCount((count) => count + 1);
this.connectionFailureCount += 1;
}
break;
}
});

this.events.on("event", (event) =>
handleEventV1(this, event, this.#setReady)
handleEventV1(
this,
event,
((value: boolean) => {
this.ready = value;
}).bind(this)
)
);
}

@@ -301,7 +292,7 @@ export class Client extends EventEmitter<Events> {
connect() {
clearTimeout(this.#reconnectTimeout);
this.events.disconnect();
this.#setReady(false);
this.ready = false;
this.events.connect(
this.configuration?.ws ?? "wss://ws.revolt.chat",
typeof this.#session === "string" ? this.#session : this.#session!.token
33 changes: 13 additions & 20 deletions src/classes/Channel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { batch } from "solid-js";

import type {
Member as ApiMember,
Message as ApiMessage,
@@ -381,10 +379,8 @@ export class Channel {
`/channels/${this.id as ""}/members`
);

return batch(() =>
members.map((user) =>
this.#collection.client.users.getOrCreate(user._id, user)
)
return members.map((user) =>
this.#collection.client.users.getOrCreate(user._id, user)
);
}

@@ -398,10 +394,8 @@ export class Channel {
`/channels/${this.id as ""}/webhooks`
);

return batch(() =>
webhooks.map((webhook) =>
this.#collection.client.channelWebhooks.getOrCreate(webhook.id, webhook)
)
return webhooks.map((webhook) =>
this.#collection.client.channelWebhooks.getOrCreate(webhook.id, webhook)
);
}

@@ -424,7 +418,7 @@ export class Channel {
});

if (this.type === "DirectMessage") {
this.#collection.updateUnderlyingObject(this.id, "active", false);
this.#collection.setUnderlyingKey(this.id, "active", false);
return;
}

@@ -549,7 +543,7 @@ export class Channel {
{ ...params, include_users: true }
)) as { messages: ApiMessage[]; users: ApiUser[]; members?: ApiMember[] };

return batch(() => ({
return {
messages: data.messages.map((message) =>
this.#collection.client.messages.getOrCreate(message._id, message)
),
@@ -559,7 +553,7 @@ export class Channel {
members: data.members?.map((member) =>
this.#collection.client.serverMembers.getOrCreate(member._id, member)
),
}));
};
}

/**
@@ -574,10 +568,8 @@ export class Channel {
params
)) as ApiMessage[];

return batch(() =>
messages.map((message) =>
this.#collection.client.messages.getOrCreate(message._id, message)
)
return messages.map((message) =>
this.#collection.client.messages.getOrCreate(message._id, message)
);
}

@@ -596,7 +588,7 @@ export class Channel {
}
)) as { messages: ApiMessage[]; users: ApiUser[]; members?: ApiMember[] };

return batch(() => ({
return {
messages: data.messages.map((message) =>
this.#collection.client.messages.getOrCreate(message._id, message)
),
@@ -606,7 +598,7 @@ export class Channel {
members: data.members?.map((member) =>
this.#collection.client.serverMembers.getOrCreate(member._id, member)
),
}));
};
}

/**
@@ -669,7 +661,8 @@ export class Channel {
const unreads = this.#collection.client.channelUnreads;
const channelUnread = unreads.get(this.id);
if (channelUnread) {
unreads.updateUnderlyingObject(this.id, {
unreads.setUnderlyingObject(this.id, {
...unreads.getUnderlyingObject(this.id),
lastMessageId,
});

2 changes: 1 addition & 1 deletion src/classes/ChannelWebhook.ts
Original file line number Diff line number Diff line change
@@ -75,14 +75,14 @@
* Edit this webhook
* TODO: not in production
*/
async edit(data: any /*: DataEditWebhook*/) {

Check warning on line 78 in src/classes/ChannelWebhook.ts

GitHub Actions / build (18.x)

Unexpected any. Specify a different type

Check warning on line 78 in src/classes/ChannelWebhook.ts

GitHub Actions / build (20.x)

Unexpected any. Specify a different type
const webhook = await this.#collection.client.api.patch(
// @ts-expect-error not in prod
`/webhooks/${this.id as ""}/${this.token as ""}`,
data
);

this.#collection.updateUnderlyingObject(
this.#collection.setUnderlyingObject(
this.id,
// @ts-expect-error not in prod
hydrate("channelWebhook", webhook, this.#collection.client)
30 changes: 20 additions & 10 deletions src/classes/MFA.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { SetStoreFunction, createStore } from "solid-js/store";

import {
MFAMethod,
MFAResponse,
@@ -14,7 +12,7 @@ import { Client } from "../index.js";
*/
export class MFA {
#client: Client;
#store: [MultiFactorStatus, SetStoreFunction<MultiFactorStatus>];
#store: MultiFactorStatus;

/**
* Construct MFA helper
@@ -23,21 +21,30 @@ export class MFA {
*/
constructor(client: Client, state: MultiFactorStatus) {
this.#client = client;
this.#store = createStore(state);
this.#store = state;
}

/**
* Mutate the store
* @param key Key
* @param value Value
*/
#mutateStore(key: keyof MultiFactorStatus, value: boolean) {
this.#store[key] = value;
}

/**
* Whether authenticator app is enabled
*/
get authenticatorEnabled() {
return this.#store[0].totp_mfa;
return this.#store.totp_mfa;
}

/**
* Whether recovery codes are enabled
*/
get recoveryEnabled() {
return this.#store[0].recovery_active;
return this.#store.recovery_active;
}

/**
@@ -59,7 +66,10 @@ export class MFA {
createTicket(params: MFAResponse) {
return this.#client.api
.put("/auth/mfa/ticket", params)
.then((ticket) => new MFATicket(this.#client, ticket, this.#store[1]));
.then(
(ticket) =>
new MFATicket(this.#client, ticket, this.#mutateStore.bind(this))
);
}

/**
@@ -68,7 +78,7 @@ export class MFA {
*/
async enableAuthenticator(token: string) {
await this.#client.api.put("/auth/mfa/totp", { totp_code: token });
this.#store[1]("totp_mfa", true);
this.#mutateStore("totp_mfa", true);
}
}

@@ -78,7 +88,7 @@ export class MFA {
export class MFATicket {
#client: Client;
#ticket: TicketType;
#mutate: SetStoreFunction<MultiFactorStatus>;
#mutate: (key: keyof MultiFactorStatus, value: boolean) => void;
#used = false;

/**
@@ -90,7 +100,7 @@ export class MFATicket {
constructor(
client: Client,
ticket: TicketType,
mutate: SetStoreFunction<MultiFactorStatus>
mutate: (key: keyof MultiFactorStatus, value: boolean) => void
) {
this.#client = client;
this.#ticket = ticket;
22 changes: 9 additions & 13 deletions src/classes/PublicInvite.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { batch } from "solid-js";

import { ServerFlags } from "../hydration/server.js";
import { API, Client, File } from "../index.js";

@@ -100,17 +98,15 @@ export class ServerPublicInvite extends PublicChannelInvite {
const invite = await this.client!.api.post(`/invites/${this.code as ""}`);

if (invite.type === "Server") {
return batch(() => {
for (const channel of invite.channels) {
this.client!.channels.getOrCreate(channel._id, channel);
}

return this.client!.servers.getOrCreate(
invite.server._id,
invite.server,
true
);
});
for (const channel of invite.channels) {
this.client!.channels.getOrCreate(channel._id, channel);
}

return this.client!.servers.getOrCreate(
invite.server._id,
invite.server,
true
);
} else {
throw "unreachable";
}
Loading