diff --git a/web/src/lib/actions/zoom-image.ts b/web/src/lib/actions/zoom-image.ts
index 20eabd892b..6288daa380 100644
--- a/web/src/lib/actions/zoom-image.ts
+++ b/web/src/lib/actions/zoom-image.ts
@@ -5,7 +5,7 @@ export const zoomImageAction = (node: HTMLElement, options?: { disabled?: boolea
const zoomInstance = createZoomImageWheel(node, { maxZoom: 10, initialState: assetViewerManager.zoomState });
const unsubscribes = [
- assetViewerManager.on('ZoomChange', (state) => zoomInstance.setState(state)),
+ assetViewerManager.on({ ZoomChange: (state) => zoomInstance.setState(state) }),
zoomInstance.subscribe(({ state }) => assetViewerManager.onZoomChange(state)),
];
diff --git a/web/src/lib/components/AssetViewerEvents.svelte b/web/src/lib/components/AssetViewerEvents.svelte
index bf915ae217..148da0e258 100644
--- a/web/src/lib/components/AssetViewerEvents.svelte
+++ b/web/src/lib/components/AssetViewerEvents.svelte
@@ -1,6 +1,6 @@
+
+const event = name.slice(2) as keyof Events;
diff --git a/web/src/lib/components/OnEvents.svelte b/web/src/lib/components/OnEvents.svelte
index aa137ccba1..fe8039cf38 100644
--- a/web/src/lib/components/OnEvents.svelte
+++ b/web/src/lib/components/OnEvents.svelte
@@ -1,5 +1,6 @@
diff --git a/web/src/lib/managers/AssetCacheManager.svelte.ts b/web/src/lib/managers/AssetCacheManager.svelte.ts
index f36f6a9a8a..f3c85acfa5 100644
--- a/web/src/lib/managers/AssetCacheManager.svelte.ts
+++ b/web/src/lib/managers/AssetCacheManager.svelte.ts
@@ -37,9 +37,11 @@ class AssetCacheManager {
#ocrCache = new AsyncCache();
constructor() {
- eventManager.on('AssetEditsApplied', () => {
- this.#assetCache.clear();
- this.#ocrCache.clear();
+ eventManager.on({
+ AssetEditsApplied: () => {
+ this.#assetCache.clear();
+ this.#ocrCache.clear();
+ },
});
}
diff --git a/web/src/lib/managers/cast-manager.svelte.ts b/web/src/lib/managers/cast-manager.svelte.ts
index 81aedd9d85..19e44b17f5 100644
--- a/web/src/lib/managers/cast-manager.svelte.ts
+++ b/web/src/lib/managers/cast-manager.svelte.ts
@@ -59,7 +59,9 @@ class CastManager {
// Add other cast destinations here (ie FCast)
];
- eventManager.on('AppInit', () => void this.initialize());
+ eventManager.on({
+ AppInit: () => void this.initialize(),
+ });
}
private async initialize() {
diff --git a/web/src/lib/managers/feature-flags-manager.svelte.ts b/web/src/lib/managers/feature-flags-manager.svelte.ts
index e27f3ff471..3e7d2e145e 100644
--- a/web/src/lib/managers/feature-flags-manager.svelte.ts
+++ b/web/src/lib/managers/feature-flags-manager.svelte.ts
@@ -5,7 +5,9 @@ class FeatureFlagsManager {
#value?: ServerFeaturesDto = $state();
constructor() {
- eventManager.on('SystemConfigUpdate', () => void this.#loadFeatureFlags());
+ eventManager.on({
+ SystemConfigUpdate: () => void this.#loadFeatureFlags(),
+ });
}
async init() {
diff --git a/web/src/lib/managers/language-manager.svelte.ts b/web/src/lib/managers/language-manager.svelte.ts
index 91d621f679..e3069e4504 100644
--- a/web/src/lib/managers/language-manager.svelte.ts
+++ b/web/src/lib/managers/language-manager.svelte.ts
@@ -4,7 +4,9 @@ import { lang } from '$lib/stores/preferences.store';
class LanguageManager {
constructor() {
- eventManager.on('AppInit', () => lang.subscribe((lang) => this.setLanguage(lang)));
+ eventManager.on({
+ AppInit: () => lang.subscribe((lang) => this.setLanguage(lang)),
+ });
}
rtl = $state(false);
diff --git a/web/src/lib/managers/queue-manager.svelte.ts b/web/src/lib/managers/queue-manager.svelte.ts
index f6bd1ad052..36e1fa905e 100644
--- a/web/src/lib/managers/queue-manager.svelte.ts
+++ b/web/src/lib/managers/queue-manager.svelte.ts
@@ -19,7 +19,9 @@ export class QueueManager {
}
constructor() {
- eventManager.on('QueueUpdate', () => this.refresh());
+ eventManager.on({
+ QueueUpdate: () => this.refresh(),
+ });
}
listen() {
diff --git a/web/src/lib/managers/release-manager.svelte.ts b/web/src/lib/managers/release-manager.svelte.ts
index 1a3108a227..15baa6de8f 100644
--- a/web/src/lib/managers/release-manager.svelte.ts
+++ b/web/src/lib/managers/release-manager.svelte.ts
@@ -5,7 +5,9 @@ class ReleaseManager {
value = $state();
constructor() {
- eventManager.on('ReleaseEvent', (event) => (this.value = event));
+ eventManager.on({
+ ReleaseEvent: (event) => (this.value = event),
+ });
}
}
diff --git a/web/src/lib/managers/server-config-manager.svelte.ts b/web/src/lib/managers/server-config-manager.svelte.ts
index e315fba818..b0e42aff3c 100644
--- a/web/src/lib/managers/server-config-manager.svelte.ts
+++ b/web/src/lib/managers/server-config-manager.svelte.ts
@@ -5,7 +5,9 @@ class ServerConfigManager {
#value?: ServerConfigDto = $state();
constructor() {
- eventManager.on('SystemConfigUpdate', () => this.loadServerConfig());
+ eventManager.on({
+ SystemConfigUpdate: () => this.loadServerConfig(),
+ });
}
async init() {
diff --git a/web/src/lib/managers/system-config-manager.svelte.ts b/web/src/lib/managers/system-config-manager.svelte.ts
index 7e80a44a0c..116137c59c 100644
--- a/web/src/lib/managers/system-config-manager.svelte.ts
+++ b/web/src/lib/managers/system-config-manager.svelte.ts
@@ -7,7 +7,9 @@ class SystemConfigManager {
#defaultValue?: SystemConfigDto = $state();
constructor() {
- eventManager.on('SystemConfigUpdate', (config) => (this.#value = config));
+ eventManager.on({
+ SystemConfigUpdate: (config) => (this.#value = config),
+ });
}
async init() {
diff --git a/web/src/lib/managers/theme-manager.svelte.ts b/web/src/lib/managers/theme-manager.svelte.ts
index 98b38b6afb..26c3fe31d5 100644
--- a/web/src/lib/managers/theme-manager.svelte.ts
+++ b/web/src/lib/managers/theme-manager.svelte.ts
@@ -37,7 +37,9 @@ class ThemeManager {
isDark = $derived(this.value === Theme.DARK);
constructor() {
- eventManager.on('AppInit', () => this.#onAppInit());
+ eventManager.on({
+ AppInit: () => this.#onAppInit(),
+ });
}
setSystem(system: boolean) {
diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
index 06601caff6..24365f41e5 100644
--- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
@@ -111,9 +111,11 @@ export class TimelineManager extends VirtualScrollManager {
constructor() {
super();
- const onAssetUpdate = (asset: AssetResponseDto) => this.upsertAssets([toTimelineAsset(asset)]);
-
- this.#unsubscribes.push(eventManager.on('AssetUpdate', onAssetUpdate));
+ this.#unsubscribes.push(
+ eventManager.on({
+ AssetUpdate: (asset: AssetResponseDto) => this.upsertAssets([toTimelineAsset(asset)]),
+ }),
+ );
}
override get scrollTop(): number {
diff --git a/web/src/lib/managers/upload-manager.svelte.ts b/web/src/lib/managers/upload-manager.svelte.ts
index 031c43b8c4..18fab1158b 100644
--- a/web/src/lib/managers/upload-manager.svelte.ts
+++ b/web/src/lib/managers/upload-manager.svelte.ts
@@ -6,7 +6,7 @@ class UploadManager {
mediaTypes = $state({ image: [], sidecar: [], video: [] });
constructor() {
- eventManager.onMany({
+ eventManager.on({
AppInit: () => this.#loadExtensions(),
AuthLogout: () => this.reset(),
});
diff --git a/web/src/lib/stores/folders.svelte.ts b/web/src/lib/stores/folders.svelte.ts
index 3480e95f28..3adebf51f9 100644
--- a/web/src/lib/stores/folders.svelte.ts
+++ b/web/src/lib/stores/folders.svelte.ts
@@ -19,7 +19,9 @@ class FoldersStore {
private assets = $state({});
constructor() {
- eventManager.on('AuthLogout', () => this.clearCache());
+ eventManager.on({
+ AuthLogout: () => this.clearCache(),
+ });
}
async fetchTree(): Promise {
diff --git a/web/src/lib/stores/memory.store.svelte.ts b/web/src/lib/stores/memory.store.svelte.ts
index 877e91a856..cdd6af9606 100644
--- a/web/src/lib/stores/memory.store.svelte.ts
+++ b/web/src/lib/stores/memory.store.svelte.ts
@@ -25,7 +25,7 @@ class MemoryStoreSvelte {
#loading: Promise | undefined;
constructor() {
- eventManager.onMany({
+ eventManager.on({
AuthLogout: () => this.clearCache(),
AuthUserLoaded: () => this.initialize(),
});
diff --git a/web/src/lib/stores/notification-manager.svelte.ts b/web/src/lib/stores/notification-manager.svelte.ts
index 9dc35a4ea6..1d1dda3d06 100644
--- a/web/src/lib/stores/notification-manager.svelte.ts
+++ b/web/src/lib/stores/notification-manager.svelte.ts
@@ -8,7 +8,7 @@ class NotificationStore {
notifications = $state([]);
constructor() {
- eventManager.onMany({
+ eventManager.on({
AuthLogin: () => this.refresh(),
AuthLogout: () => this.clear(),
});
diff --git a/web/src/lib/stores/search.svelte.ts b/web/src/lib/stores/search.svelte.ts
index 007c764fcf..453a8ce6c6 100644
--- a/web/src/lib/stores/search.svelte.ts
+++ b/web/src/lib/stores/search.svelte.ts
@@ -5,7 +5,9 @@ class SearchStore {
isSearchEnabled = $state(false);
constructor() {
- eventManager.on('AuthLogout', () => this.clearCache());
+ eventManager.on({
+ AuthLogout: () => this.clearCache(),
+ });
}
clearCache() {
diff --git a/web/src/lib/stores/user.store.ts b/web/src/lib/stores/user.store.ts
index bc23917d22..331df7ad5f 100644
--- a/web/src/lib/stores/user.store.ts
+++ b/web/src/lib/stores/user.store.ts
@@ -16,4 +16,6 @@ export const resetSavedUser = () => {
purchaseStore.setPurchaseStatus(false);
};
-eventManager.on('AuthLogout', () => resetSavedUser());
+eventManager.on({
+ AuthLogout: () => resetSavedUser(),
+});
diff --git a/web/src/lib/stores/user.svelte.ts b/web/src/lib/stores/user.svelte.ts
index f9319fcfa1..508fd156b8 100644
--- a/web/src/lib/stores/user.svelte.ts
+++ b/web/src/lib/stores/user.svelte.ts
@@ -26,4 +26,6 @@ const reset = () => {
Object.assign(userInteraction, defaultUserInteraction);
};
-eventManager.on('AuthLogout', () => reset());
+eventManager.on({
+ AuthLogout: () => reset(),
+});
diff --git a/web/src/lib/utils/base-event-manager.svelte.ts b/web/src/lib/utils/base-event-manager.svelte.ts
index 89a5c7390e..1b5135dfd9 100644
--- a/web/src/lib/utils/base-event-manager.svelte.ts
+++ b/web/src/lib/utils/base-event-manager.svelte.ts
@@ -1,8 +1,9 @@
-type EventMap = Record;
+type EventsBase = Record;
type PromiseLike = Promise | T;
-export type EventCallback = (...args: E[T]) => PromiseLike;
-export type EventItem = {
+export type EventMap = { [K in keyof E]?: EventCallback };
+export type EventCallback = (...args: E[T]) => PromiseLike;
+export type EventItem = {
id: number;
event: T;
callback: EventCallback;
@@ -13,10 +14,22 @@ const nextId = () => count++;
const noop = () => {};
-export class BaseEventManager {
+export class BaseEventManager {
#callbacks: EventItem[] = $state([]);
- on(event: T, callback?: EventCallback) {
+ on(subscriptions: EventMap): () => void {
+ const cleanups = Object.entries(subscriptions).map(([event, callback]) =>
+ this.#onEvent(event as keyof Events, callback as EventCallback),
+ );
+
+ return () => {
+ for (const cleanup of cleanups) {
+ cleanup();
+ }
+ };
+ }
+
+ #onEvent(event: T, callback?: EventCallback) {
if (!callback) {
return noop;
}
@@ -30,17 +43,6 @@ export class BaseEventManager {
};
}
- onMany(subscriptions: { [T in keyof Events]?: EventCallback }) {
- const cleanups = Object.entries(subscriptions).map(([event, callback]) =>
- this.on(event as keyof Events, callback as EventCallback),
- );
- return () => {
- for (const cleanup of cleanups) {
- cleanup();
- }
- };
- }
-
emit(event: T, ...params: Events[T]) {
const listeners = this.getListeners(event);
for (const listener of listeners) {