This commit is contained in:
2025-05-21 08:52:33 +03:00
parent e992d388fb
commit 4e5fca2402
68 changed files with 358 additions and 1398 deletions

View File

@@ -1,11 +1,7 @@
import axios from "../http-client";
import { messageSchema, type ChannelId, type Uuid } from "../types";
export async function paginatedMessages(
channelId: ChannelId,
limit: number,
before: ChannelId | undefined,
) {
export async function paginatedMessages(channelId: ChannelId, limit: number, before: ChannelId | undefined) {
const response = await axios.get(`/channels/${channelId}/messages`, {
params: {
limit,
@@ -13,16 +9,10 @@ export async function paginatedMessages(
},
});
return (response.data as any[]).map((value, _) =>
messageSchema.parse(value),
);
return (response.data as any[]).map((value, _) => messageSchema.parse(value));
}
export async function sendMessage(
channelId: ChannelId,
content: string,
attachments?: Uuid[],
) {
export async function sendMessage(channelId: ChannelId, content: string, attachments?: Uuid[]) {
const response = await axios.post(`/channels/${channelId}/messages`, {
content,
attachments,

View File

@@ -1,12 +1,5 @@
import axios from "../http-client";
import type {
ChannelId,
ChannelType,
Server,
ServerChannel,
ServerId,
ServerInvite,
} from "../types";
import type { ChannelId, ChannelType, Server, ServerChannel, ServerId, ServerInvite } from "../types";
interface CreateServerRequest {
name: string;
@@ -48,27 +41,20 @@ export async function listChannels(serverId: ServerId) {
return response.data as ServerChannel[];
}
export async function createChannel(
serverId: ServerId,
request: CreateServerChannelRequest,
) {
export async function createChannel(serverId: ServerId, request: CreateServerChannelRequest) {
const response = await axios.post(`/servers/${serverId}/channels`, request);
return response.data as ServerChannel;
}
export async function getChannel(serverId: ServerId, channelId: ChannelId) {
const response = await axios.get(
`/servers/${serverId}/channels/${channelId}`,
);
const response = await axios.get(`/servers/${serverId}/channels/${channelId}`);
return response.data as ServerChannel;
}
export async function deleteChannel(serverId: ServerId, channelId: ChannelId) {
const response = await axios.delete(
`/servers/${serverId}/channels/${channelId}`,
);
const response = await axios.delete(`/servers/${serverId}/channels/${channelId}`);
return response.data as ServerChannel;
}

View File

@@ -1,11 +1,5 @@
import axios from "../http-client";
import type {
FullUser,
PartialUser,
RecipientChannel,
UserId,
Uuid,
} from "../types";
import type { FullUser, PartialUser, RecipientChannel, UserId, Uuid } from "../types";
export async function me() {
const response = await axios.get("/users/@me");

View File

@@ -5,9 +5,7 @@ export type TypeToZod<T> = {
? undefined extends T[K]
? E extends object
? z.ZodOptional<z.ZodArray<z.ZodObject<TypeToZod<E>>>>
: z.ZodOptional<
z.ZodArray<z.ZodType<Exclude<E, null | undefined>>>
>
: z.ZodOptional<z.ZodArray<z.ZodType<Exclude<E, null | undefined>>>>
: E extends object
? z.ZodArray<z.ZodObject<TypeToZod<E>>>
: z.ZodArray<z.ZodType<Exclude<E, null | undefined>>>

View File

@@ -32,11 +32,7 @@ export function createPrefixedLogger(prefix: string, styles?: string[]) {
result[methodName] = (...args: any[]) => {
if (typeof args[0] === "string") {
originalMethod(
`${prefix} ${args[0]}`,
...(styles || []),
...args.slice(1),
);
originalMethod(`${prefix} ${args[0]}`, ...(styles || []), ...args.slice(1));
} else {
originalMethod(prefix, styles, ...args);
}

View File

@@ -102,10 +102,7 @@ export class GatewayClient {
});
}
public onEvent<K extends keyof GatewayEvents>(
event: K | string,
handler: GatewayEvents[K],
): void {
public onEvent<K extends keyof GatewayEvents>(event: K | string, handler: GatewayEvents[K]): void {
this.serverEventHandlers[event as K] = handler;
}
@@ -113,10 +110,7 @@ export class GatewayClient {
delete this.serverEventHandlers[event];
}
public onControl<K extends keyof ControlEvents>(
event: K,
handler: ControlEvents[K],
): void {
public onControl<K extends keyof ControlEvents>(event: K, handler: ControlEvents[K]): void {
this.eventHandlers[event] = handler;
}
@@ -226,11 +220,7 @@ export class GatewayClient {
this.userId = message.data.userId;
this.sessionKey = message.data.sessionKey;
this.setState(ConnectionState.CONNECTED);
this.emitControl(
"authenticated",
message.data.userId,
message.data.sessionKey,
);
this.emitControl("authenticated", message.data.userId, message.data.sessionKey);
break;
case ServerMessageType.AUTHENTICATE_DENIED:
@@ -239,10 +229,7 @@ export class GatewayClient {
break;
case ServerMessageType.ERROR:
this.emitError(
new Error(`Server error: ${message.data.code}`),
message.data.code,
);
this.emitError(new Error(`Server error: ${message.data.code}`), message.data.code);
break;
case ServerMessageType.EVENT:
@@ -264,9 +251,7 @@ export class GatewayClient {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(message));
} else {
this.emitError(
new Error("Cannot send message: socket not connected"),
);
this.emitError(new Error("Cannot send message: socket not connected"));
}
}
@@ -286,20 +271,14 @@ export class GatewayClient {
this.emitControl("error", error, code);
}
private emitControl<K extends keyof ControlEvents>(
event: K,
...args: Parameters<ControlEvents[K]>
): void {
private emitControl<K extends keyof ControlEvents>(event: K, ...args: Parameters<ControlEvents[K]>): void {
const handler = this.eventHandlers[event];
if (handler) {
(handler as Function)(...args);
}
}
private emitEvent<K extends keyof GatewayEvents>(
event: K,
...args: Parameters<GatewayEvents[K]>
): void {
private emitEvent<K extends keyof GatewayEvents>(event: K, ...args: Parameters<GatewayEvents[K]>): void {
const handler = this.serverEventHandlers[event];
if (handler) {
(handler as Function)(...args);
@@ -322,10 +301,7 @@ export class GatewayClient {
this.socket.onclose = null;
// Close the connection if it's still open
if (
this.socket.readyState === WebSocket.OPEN ||
this.socket.readyState === WebSocket.CONNECTING
) {
if (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) {
this.socket.close();
}
@@ -337,7 +313,4 @@ export class GatewayClient {
}
}
const logger = createPrefixedLogger("%cGateway WS%c:", [
"color: red; font-weight: bold;",
"",
]);
const logger = createPrefixedLogger("%cGateway WS%c:", ["color: red; font-weight: bold;", ""]);

View File

@@ -1,12 +1,4 @@
import type {
ChannelId,
Message,
MessageId,
PartialUser,
Server,
ServerId,
UserId,
} from "~/lib/api/types";
import type { ChannelId, Message, MessageId, PartialUser, Server, ServerId, UserId } from "~/lib/api/types";
type Channel = any; // TODO: Define Channel type
@@ -78,10 +70,7 @@ export interface RequestVoiceStatesMessage {
};
}
export type ClientMessage =
| AuthenticateMessage
| VoiceStateUpdateMessage
| RequestVoiceStatesMessage;
export type ClientMessage = AuthenticateMessage | VoiceStateUpdateMessage | RequestVoiceStatesMessage;
// Server message types
export interface AuthenticateAcceptedMessage {
@@ -245,11 +234,7 @@ export interface EventMessage {
};
}
export type ServerMessage =
| AuthenticateAcceptedMessage
| AuthenticateDeniedMessage
| EventMessage
| ErrorMessage;
export type ServerMessage = AuthenticateAcceptedMessage | AuthenticateDeniedMessage | EventMessage | ErrorMessage;
// Connection states
export enum ConnectionState {

View File

@@ -1,11 +1,5 @@
import { createPrefixedLogger } from "~/lib/utils";
import {
ClientMessageType,
ConnectionState,
ServerMessageType,
type ClientMessage,
type ServerMessage,
} from "./types";
import { ClientMessageType, ConnectionState, ServerMessageType, type ClientMessage, type ServerMessage } from "./types";
export class WebRTCClient {
private socket: WebSocket | null = null;
@@ -42,10 +36,7 @@ export class WebRTCClient {
this.connectionLock = true;
if (
this.state !== ConnectionState.DISCONNECTED &&
this.state !== ConnectionState.ERROR
) {
if (this.state !== ConnectionState.DISCONNECTED && this.state !== ConnectionState.ERROR) {
this.disconnect();
}
@@ -97,9 +88,7 @@ export class WebRTCClient {
}
};
} catch (error) {
this.handleError(
error instanceof Error ? error : new Error("Unknown error"),
);
this.handleError(error instanceof Error ? error : new Error("Unknown error"));
}
};
@@ -190,17 +179,11 @@ export class WebRTCClient {
});
}
} catch (error) {
this.handleError(
error instanceof Error
? error
: new Error("Error creating WebRTC offer"),
);
this.handleError(error instanceof Error ? error : new Error("Error creating WebRTC offer"));
}
};
private handleServerMessage = async (
event: MessageEvent,
): Promise<void> => {
private handleServerMessage = async (event: MessageEvent): Promise<void> => {
try {
const message: ServerMessage = JSON.parse(event.data);
@@ -223,17 +206,11 @@ export class WebRTCClient {
warn("Unhandled message type:", message);
}
} catch (error) {
this.handleError(
error instanceof Error
? error
: new Error("Failed to process message"),
);
this.handleError(error instanceof Error ? error : new Error("Failed to process message"));
}
};
private handleSdpAnswer = async (
sdp: RTCSessionDescription,
): Promise<void> => {
private handleSdpAnswer = async (sdp: RTCSessionDescription): Promise<void> => {
log("Received SDP answer: %o", sdp);
if (!this.peerConnection) {
@@ -244,11 +221,7 @@ export class WebRTCClient {
try {
await this.peerConnection.setRemoteDescription(sdp);
} catch (error) {
this.handleError(
error instanceof Error
? error
: new Error("Error setting remote description"),
);
this.handleError(error instanceof Error ? error : new Error("Error setting remote description"));
}
};
@@ -258,9 +231,7 @@ export class WebRTCClient {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(message));
} else {
this.handleError(
new Error("Cannot send message: socket not connected"),
);
this.handleError(new Error("Cannot send message: socket not connected"));
}
};
@@ -293,7 +264,4 @@ export class WebRTCClient {
};
}
const { log, warn, ...other } = createPrefixedLogger("%cWebRTC WS%c:", [
"color: blue; font-weight: bold;",
"",
]);
const { log, warn, ...other } = createPrefixedLogger("%cWebRTC WS%c:", ["color: blue; font-weight: bold;", ""]);