import type { ThemeSetting } from '$lib/managers/theme-manager.svelte'; import type { ReleaseEvent } from '$lib/types'; import type { AlbumResponseDto, ApiKeyResponseDto, AssetResponseDto, LibraryResponseDto, LoginResponseDto, QueueResponseDto, SharedLinkResponseDto, SystemConfigDto, UserAdminResponseDto, WorkflowResponseDto, } from '@immich/sdk'; export type Events = { AppInit: []; UserLogin: []; AuthLogin: [LoginResponseDto]; AuthLogout: []; LanguageChange: [{ name: string; code: string; rtl?: boolean }]; ThemeChange: [ThemeSetting]; ApiKeyCreate: [ApiKeyResponseDto]; ApiKeyUpdate: [ApiKeyResponseDto]; ApiKeyDelete: [ApiKeyResponseDto]; AssetUpdate: [AssetResponseDto]; AssetReplace: [{ oldAssetId: string; newAssetId: string }]; AlbumUpdate: [AlbumResponseDto]; AlbumDelete: [AlbumResponseDto]; QueueUpdate: [QueueResponseDto]; SharedLinkCreate: [SharedLinkResponseDto]; SharedLinkUpdate: [SharedLinkResponseDto]; SharedLinkDelete: [SharedLinkResponseDto]; UserAdminCreate: [UserAdminResponseDto]; UserAdminUpdate: [UserAdminResponseDto]; UserAdminRestore: [UserAdminResponseDto]; // soft deleted UserAdminDelete: [UserAdminResponseDto]; // confirmed permanently deleted from server UserAdminDeleted: [{ id: string }]; SystemConfigUpdate: [SystemConfigDto]; LibraryCreate: [LibraryResponseDto]; LibraryUpdate: [LibraryResponseDto]; LibraryDelete: [{ id: string }]; WorkflowUpdate: [WorkflowResponseDto]; WorkflowDelete: [WorkflowResponseDto]; ReleaseEvent: [ReleaseEvent]; }; type Listener, K extends keyof EventMap> = (...params: EventMap[K]) => void; class EventManager> { private listeners: { [K in keyof EventMap]?: { listener: Listener; once?: boolean; }[]; } = {}; on(key: T, listener: (...params: EventMap[T]) => void) { return this.addListener(key, listener, false); } once(key: T, listener: (...params: EventMap[T]) => void) { return this.addListener(key, listener, true); } off(key: K, listener: Listener) { if (this.listeners[key]) { this.listeners[key] = this.listeners[key].filter((item) => item.listener !== listener); } return this; } emit(key: T, ...params: EventMap[T]) { if (!this.listeners[key]) { return; } for (const { listener } of this.listeners[key]) { listener(...params); } // remove one time listeners this.listeners[key] = this.listeners[key].filter((item) => !item.once); } private addListener(key: T, listener: (...params: EventMap[T]) => void, once: boolean) { if (!this.listeners[key]) { this.listeners[key] = []; } this.listeners[key].push({ listener, once }); return this; } } export const eventManager = new EventManager();