BREAKING CHANGE: remove isomorphic-ws, long, eventemitter3

This commit is contained in:
Jersey
2025-03-14 13:01:32 -04:00
parent 63c2b643ec
commit 5397269ae6
5 changed files with 1872 additions and 1549 deletions
+3 -7
View File
@@ -28,13 +28,10 @@
"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",
"@vladfrangu/async_event_emitter": "^2.4.6",
"revolt-api": "0.8.3",
"solid-js": "^1.8.15",
"ulid": "^2.3.0",
"ws": "^8.16.0"
"ulid": "^2.3.0"
},
"devDependencies": {
"@mxssfd/typedoc-theme": "^1.1.3",
@@ -50,8 +47,7 @@
"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"
}
}
}
+1789 -1451
View File
File diff suppressed because it is too large Load Diff
+50 -52
View File
@@ -1,7 +1,7 @@
import { Accessor, Setter, batch, createSignal } from "solid-js";
import { Accessor, batch, createSignal, Setter } from "solid-js";
import EventEmitter from "eventemitter3";
import type { DataLogin, Error, RevoltConfig } from "revolt-api";
import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter";
import type { DataLogin, RevoltConfig } from "revolt-api";
import { API, Role } from "revolt-api";
import {
@@ -48,55 +48,52 @@ export type Session = { _id: string; token: string; user_id: string } | string;
*/
export type Events = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error(error: any): void;
error: [error: any];
connected(): void;
connecting(): void;
disconnected(): void;
ready(): void;
logout(): void;
connected: [];
connecting: [];
disconnected: [];
ready: [];
logout: [];
messageCreate(message: Message): void;
messageUpdate(message: Message, previousMessage: HydratedMessage): void;
messageDelete(message: HydratedMessage): void;
messageDeleteBulk(messages: HydratedMessage[], channel?: Channel): void;
messageReactionAdd(message: Message, userId: string, emoji: string): void;
messageReactionRemove(message: Message, userId: string, emoji: string): void;
messageReactionRemoveEmoji(message: Message, emoji: string): void;
messageCreate: [message: Message];
messageUpdate: [message: Message, previousMessage: HydratedMessage];
messageDelete: [message: HydratedMessage];
messageDeleteBulk: [messages: HydratedMessage[], channel?: Channel];
messageReactionAdd: [message: Message, userId: string, emoji: string];
messageReactionRemove: [message: Message, userId: string, emoji: string];
messageReactionRemoveEmoji: [message: Message, emoji: string];
channelCreate(channel: Channel): void;
channelUpdate(channel: Channel, previousChannel: HydratedChannel): void;
channelDelete(channel: HydratedChannel): void;
channelGroupJoin(channel: Channel, user: User): void;
channelGroupLeave(channel: Channel, user?: User): void;
channelStartTyping(channel: Channel, user?: User): void;
channelStopTyping(channel: Channel, user?: User): void;
channelAcknowledged(channel: Channel, messageId: string): void;
channelCreate: [channel: Channel];
channelUpdate: [channel: Channel, previousChannel: HydratedChannel];
channelDelete: [channel: HydratedChannel];
channelGroupJoin: [channel: Channel, user: User];
channelGroupLeave: [channel: Channel, user?: User];
channelStartTyping: [channel: Channel, user?: User];
channelStopTyping: [channel: Channel, user?: User];
channelAcknowledged: [channel: Channel, messageId: string];
serverCreate(server: Server): void;
serverUpdate(server: Server, previousServer: HydratedServer): void;
serverDelete(server: HydratedServer): void;
serverLeave(server: HydratedServer): void;
serverRoleUpdate(server: Server, roleId: string, previousRole: Role): void;
serverRoleDelete(server: Server, roleId: string, role: Role): void;
serverCreate: [server: Server];
serverUpdate: [server: Server, previousServer: HydratedServer];
serverDelete: [server: HydratedServer];
serverLeave: [server: HydratedServer];
serverRoleUpdate: [server: Server, roleId: string, previousRole: Role];
serverRoleDelete: [server: Server, roleId: string, role: Role];
serverMemberUpdate(
serverMemberUpdate: [
member: ServerMember,
previousMember: HydratedServerMember
): void;
serverMemberJoin(member: ServerMember): void;
serverMemberLeave(member: HydratedServerMember): void;
previousMember: HydratedServerMember,
];
serverMemberJoin: [member: ServerMember];
serverMemberLeave: [member: HydratedServerMember];
userUpdate(user: User, previousUser: HydratedUser): void;
// ^ userRelationshipChanged(user: User, previousRelationship: RelationshipStatus): void;
// ^ userPresenceChanged(user: User, previousPresence: boolean): void;
userSettingsUpdate(
id: string,
update: Record<string, [number, string]>
): void;
userUpdate: [user: User, previousUser: HydratedUser];
// ^ userRelationshipChanged: [user: User, previousRelationship: RelationshipStatus];
// ^ userPresenceChanged: [user: User, previousPresence: boolean];
userSettingsUpdate: [id: string, update: Record<string, [number, string]>];
emojiCreate(emoji: Emoji): void;
emojiDelete(emoji: HydratedEmoji): void;
emojiCreate: [emoji: Emoji];
emojiDelete: [emoji: HydratedEmoji];
};
/**
@@ -159,7 +156,7 @@ export type ClientOptions = Partial<EventClientOptions> & {
/**
* Revolt.js Clients
*/
export class Client extends EventEmitter<Events> {
export class Client extends AsyncEventEmitter<Events> {
readonly account;
readonly bots;
readonly channels;
@@ -265,7 +262,7 @@ export class Client extends EventEmitter<Events> {
this.#reconnectTimeout = setTimeout(
() => this.connect(),
this.options.retryDelayFunction(this.connectionFailureCount()) *
1e3
1e3,
) as never;
this.#setConnectionFailureCount((count) => count + 1);
@@ -274,8 +271,9 @@ export class Client extends EventEmitter<Events> {
}
});
this.events.on("event", (event) =>
handleEventV1(this, event, this.#setReady)
this.events.on(
"event",
(event) => handleEventV1(this, event, this.#setReady),
);
}
@@ -304,7 +302,7 @@ export class Client extends EventEmitter<Events> {
this.#setReady(false);
this.events.connect(
this.configuration?.ws ?? "wss://ws.revolt.chat",
typeof this.#session === "string" ? this.#session : this.#session!.token
typeof this.#session === "string" ? this.#session : this.#session!.token,
);
}
@@ -399,9 +397,9 @@ export class Client extends EventEmitter<Events> {
*/
proxyFile(url: string): string | undefined {
if (this.configuration?.features.january.enabled) {
return `${
this.configuration.features.january.url
}/proxy?url=${encodeURIComponent(url)}`;
return `${this.configuration.features.january.url}/proxy?url=${
encodeURIComponent(url)
}`;
} else {
return url;
}
+15 -19
View File
@@ -1,7 +1,6 @@
import { Accessor, Setter, createSignal } from "solid-js";
import { Accessor, createSignal, Setter } from "solid-js";
import EventEmitter from "eventemitter3";
import WebSocket from "isomorphic-ws";
import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter";
import { Error } from "revolt-api";
import type { AvailableProtocols, EventProtocol } from "./index.js";
@@ -49,17 +48,18 @@ export interface EventClientOptions {
* Events provided by the client.
*/
type Events<T extends AvailableProtocols, P extends EventProtocol<T>> = {
error: (error: Error) => void;
event: (event: P["server"]) => void;
state: (state: ConnectionState) => void;
error: [error: Error];
event: [event: P["server"]];
state: [state: ConnectionState];
};
/**
* Simple wrapper around the Revolt websocket service.
*/
export class EventClient<T extends AvailableProtocols> extends EventEmitter<
Events<T, EventProtocol<T>>
> {
export class EventClient<T extends AvailableProtocols>
extends AsyncEventEmitter<
Events<T, EventProtocol<T>>
> {
readonly options: EventClientOptions;
#protocolVersion: T;
@@ -77,7 +77,7 @@ export class EventClient<T extends AvailableProtocols> extends EventEmitter<
#connectTimeoutReference: number | undefined;
#lastError: // eslint-disable-next-line @typescript-eslint/no-explicit-any
{ type: "socket"; data: any } | { type: "revolt"; data: Error } | undefined;
{ type: "socket"; data: any } | { type: "revolt"; data: Error } | undefined;
/**
* Create a new event client.
@@ -88,7 +88,7 @@ export class EventClient<T extends AvailableProtocols> extends EventEmitter<
constructor(
protocolVersion: T,
transportFormat: "json" = "json",
options?: Partial<EventClientOptions>
options?: Partial<EventClientOptions>,
) {
super();
@@ -135,13 +135,11 @@ export class EventClient<T extends AvailableProtocols> extends EventEmitter<
this.#connectTimeoutReference = setTimeout(
() => this.disconnect(),
this.options.pongTimeout * 1e3
this.options.pongTimeout * 1e3,
) as never;
this.#socket = new WebSocket(
`${uri}?version=${this.#protocolVersion}&format=${
this.#transportFormat
}&token=${token}`
`${uri}?version=${this.#protocolVersion}&format=${this.#transportFormat}&token=${token}`,
);
this.#socket.onopen = () => {
@@ -149,7 +147,7 @@ export class EventClient<T extends AvailableProtocols> extends EventEmitter<
this.send({ type: "Ping", data: +new Date() });
this.#pongTimeoutReference = setTimeout(
() => this.disconnect(),
this.options.pongTimeout * 1e3
this.options.pongTimeout * 1e3,
) as never;
}, this.options.heartbeatInterval * 1e3) as never;
};
@@ -249,9 +247,7 @@ export class EventClient<T extends AvailableProtocols> extends EventEmitter<
}
break;
default:
throw `Unreachable code. Received ${
event.type
} in state ${this.state()}.`;
throw `Unreachable code. Received ${event.type} in state ${this.state()}.`;
}
}
+15 -20
View File
@@ -1,5 +1,3 @@
import Long from "long";
import { Channel, Client, Server, ServerMember } from "../index.js";
import {
@@ -16,8 +14,8 @@ import {
* @param b Inputs (OR'd together)
*/
export function bitwiseAndEq(a: number, ...b: number[]) {
const value = b.reduce((prev, cur) => prev.or(cur), Long.fromNumber(0));
return value.and(a).eq(value);
const value = b.reduce((prev, cur) => prev | BigInt(cur), 0n);
return (value & BigInt(a)) === value;
}
/**
@@ -33,7 +31,7 @@ export function calculatePermission(
* Pretend to be another ServerMember
*/
member?: ServerMember;
}
},
): number {
const user = options?.member ? options?.member.user : client.user;
if (user?.privileged) {
@@ -55,26 +53,26 @@ export function calculatePermission(
if (!member) return 0;
// 3. Apply allows from default_permissions.
let perm = Long.fromNumber(target.defaultPermissions);
let perm = BigInt(target.defaultPermissions);
// 4. If user has roles, iterate in order.
if (member.roles && target.roles) {
// 5. Apply allows and denies from roles.
const permissions = member.orderedRoles.map(
(role) => role.permissions ?? { a: 0, d: 0 }
(role) => role.permissions ?? { a: 0, d: 0 },
);
for (const permission of permissions) {
perm = perm.or(permission.a).and(Long.fromNumber(permission.d).not());
perm = (perm | BigInt(permission.a)) & (~BigInt(permission.d));
}
}
// 5. Revoke permissions if ServerMember is timed out.
if (member.timeout && member.timeout > new Date()) {
perm = perm.and(ALLOW_IN_TIMEOUT);
perm = perm & BigInt(ALLOW_IN_TIMEOUT);
}
return perm.toNumber();
return Number(perm);
}
} else {
// 1. Check channel type.
@@ -121,15 +119,14 @@ export function calculatePermission(
if (!member) return 0;
// 5. Calculate server base permissions.
let perm = Long.fromNumber(
calculatePermission(client, server, options)
let perm = BigInt(
calculatePermission(client, server, options),
);
// 6. Apply default allows and denies for channel.
if (target.defaultPermissions) {
perm = perm
.or(target.defaultPermissions.a)
.and(Long.fromNumber(target.defaultPermissions.d).not());
perm = (perm | BigInt(target.defaultPermissions.a)) &
(~BigInt(target.defaultPermissions.d));
}
// 7. If user has roles, iterate in order.
@@ -140,19 +137,17 @@ export function calculatePermission(
for (const id of roles) {
const override = target.rolePermissions[id];
if (override) {
perm = perm
.or(override.a)
.and(Long.fromNumber(override.d).not());
perm = (perm & BigInt(override.a)) & (~BigInt(override.d));
}
}
}
// 8. Revoke permissions if ServerMember is timed out.
if (member.timeout && member.timeout > new Date()) {
perm = perm.and(ALLOW_IN_TIMEOUT);
perm = perm & BigInt(ALLOW_IN_TIMEOUT);
}
return perm.toNumber();
return Number(perm);
}
}
}