import { Observable } from "@noya-app/observable"; import type { WorkspaceMemberUser } from "./rpc/routes"; import type { RPCManager } from "./rpcManager"; import { clientId$ } from "./sync"; import type { MultiplayerUser } from "./sync/types"; export function findNoyaUser( users: MultiplayerUser[], id: string ): MultiplayerUser; export function findNoyaUser( users: MultiplayerUser[], id?: string ): MultiplayerUser | undefined; export function findNoyaUser( users: MultiplayerUser[], id?: string ): MultiplayerUser | undefined { let user: MultiplayerUser | undefined; let connection: MultiplayerUser | undefined; let client: MultiplayerUser | undefined; for (const u of users) { if (u.authId === id) { user = u; } if (u.clientId === id) { client = u; } if (u.connectionId === id) { connection = u; } } return user ?? client ?? connection; } export class UserManager { constructor(private rpcManager?: RPCManager) {} currentUserId$ = new Observable(undefined); currentClientId$ = clientId$; currentConnectionId$ = new Observable(undefined); /** * Get the best id we have for the current user. * The user id (signed in) > client id (browser storage) > connection id (websocket connection) */ currentId$ = Observable.combine( [this.currentUserId$, this.currentClientId$, this.currentConnectionId$], ([userId, clientId, connectionId]) => userId ?? clientId ?? connectionId ); allUsers$ = new Observable([]); connectedUsers$ = new Observable([]); connectedUsersCount$ = this.connectedUsers$.map((users) => users.length); currentUser$ = Observable.combine( [this.currentId$, this.allUsers$], ([id, users]) => findNoyaUser(users, id) ); workspaceUsers$ = new Observable([]); #workspaceUsersInitialized = false; initializeWorkspaceUsers() { if (this.#workspaceUsersInitialized || !this.rpcManager) return; this.#workspaceUsersInitialized = true; this.fetchWorkspaceMembers().catch((error) => { console.error("Failed to fetch workspace members", error); this.#workspaceUsersInitialized = false; }); } setCurrentUserId(userId: string | undefined) { this.currentUserId$.set(userId); } setCurrentConnectionId(connectionId: string | undefined) { this.currentConnectionId$.set(connectionId); } setAllUsers(users: MultiplayerUser[]) { this.allUsers$.set(users); this.connectedUsers$.set(users.filter((user) => !user.inactive)); } private async fetchWorkspaceMembers() { if (!this.rpcManager) return; const response = await this.rpcManager.requestRoute( "GET /api/file/members" ); const users = (this.rpcManager.getResponseBody(response) as | WorkspaceMemberUser[] | undefined) ?? []; this.workspaceUsers$.set(users); } }