From 23eb3c5a2feb49cfb146e7afd6425cc1a5af93e9 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sun, 25 Oct 2026 02:06:35 +0200 Subject: [PATCH] fix: start plugins after signing in, not only after the next reload --- lib/__tests__/plugin-store.test.ts | 15 +++++++++++++++ stores/plugin-store.ts | 11 ++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/__tests__/plugin-store.test.ts b/lib/__tests__/plugin-store.test.ts index 4a8e602ac..08ff4b611 100644 --- a/lib/__tests__/plugin-store.test.ts +++ b/lib/__tests__/plugin-store.test.ts @@ -238,6 +238,21 @@ describe('usePluginStore', () => { expect(usePluginStore.getState().plugins[0].bundleHash).toBe('hash-v1'); }); + it('starts the plugins after a sign-in when the first call ran signed out', async () => { + const { loadPlugin } = await import('@/lib/plugin-loader'); + // The mail view mounts before the user has signed in. + mocks.apiFetch.mockResolvedValueOnce({ ok: false, status: 401, json: async () => ({ error: 'Not authenticated' }) }); + + await usePluginStore.getState().initializePlugins(); + expect(usePluginStore.getState().initialized).toBe(false); + expect(loadPlugin).not.toHaveBeenCalled(); + + // plugin-app-events calls again once the user is signed in. + await usePluginStore.getState().initializePlugins(); + expect(loadPlugin).toHaveBeenCalledWith(expect.objectContaining({ id: 'managed-plugin' })); + expect(usePluginStore.getState().initialized).toBe(true); + }); + it('keeps the record when the download fails so the error can surface at load time', async () => { usePluginStore.setState({ plugins: [syncedRecord()] }); mocks.downloadManagedBundle.mockRejectedValue(new Error('Could not download the bundle (HTTP 503)')); diff --git a/stores/plugin-store.ts b/stores/plugin-store.ts index 016e08980..c234767cc 100644 --- a/stores/plugin-store.ts +++ b/stores/plugin-store.ts @@ -301,8 +301,12 @@ export const usePluginStore = create()( }); } - // Sync server-managed plugins before loading - await syncServerPlugins(get, set); + // Sync server-managed plugins before loading. The mail view starts + // this on mount, before the user has signed in; marking the store + // initialized then left every plugin off after the sign-in until + // the next page load. Stay uninitialized so the call that follows + // the sign-in (plugin-app-events) starts them. + if (await syncServerPlugins(get, set) === 'signed-out') return; // Load all enabled plugins in parallel. Sequential `await` made one // hung/slow plugin block every subsequent one; loadSandboxedPlugin @@ -502,9 +506,10 @@ function markServerManagedPlugins(plugins: InstalledPlugin[]): InstalledPlugin[] async function syncServerPlugins( get: () => PluginStoreState, set: (partial: Partial | ((state: PluginStoreState) => Partial)) => void, -): Promise { +): Promise<'signed-out' | void> { try { const res = await apiFetch('/api/plugins'); + if (res.status === 401) return 'signed-out'; if (!res.ok) return; const data: { plugins: ServerPluginInfo[] } = await res.json();