From 6a9255dfeda623ef184aa55fba4aa836878c7a80 Mon Sep 17 00:00:00 2001 From: Hakan Shehu Date: Thu, 15 Jan 2026 23:40:07 +0100 Subject: [PATCH] Fix cleanup on account logout (#296) --- .../src/services/accounts/account-service.ts | 18 +++++++++++-- packages/client/src/services/app-service.ts | 2 ++ .../services/workspaces/workspace-service.ts | 13 +++++++++- packages/ui/src/collections/index.ts | 26 +++++++++++++++++++ .../ui/src/components/app/app-provider.tsx | 1 + 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/packages/client/src/services/accounts/account-service.ts b/packages/client/src/services/accounts/account-service.ts index 3eff15b1..a26d18d3 100644 --- a/packages/client/src/services/accounts/account-service.ts +++ b/packages/client/src/services/accounts/account-service.ts @@ -4,7 +4,11 @@ import ms from 'ms'; import { SelectWorkspace } from '@colanode/client/databases'; import { eventBus } from '@colanode/client/lib/event-bus'; import { parseApiError } from '@colanode/client/lib/ky'; -import { mapAccount, mapWorkspace } from '@colanode/client/lib/mappers'; +import { + mapAccount, + mapMetadata, + mapWorkspace, +} from '@colanode/client/lib/mappers'; import { AccountSocket } from '@colanode/client/services/accounts/account-socket'; import { AppService } from '@colanode/client/services/app-service'; import { ServerService } from '@colanode/client/services/server-service'; @@ -117,11 +121,21 @@ export class AccountService { throw new Error('Failed to delete account'); } - await this.app.database + const deletedMetadata = await this.app.database .deleteFrom('metadata') + .returningAll() .where('namespace', '=', this.account.id) .execute(); + if (deletedMetadata.length > 0) { + for (const metadata of deletedMetadata) { + eventBus.publish({ + type: 'metadata.deleted', + metadata: mapMetadata(metadata), + }); + } + } + await this.app.jobs.addJob( { type: 'token.delete', diff --git a/packages/client/src/services/app-service.ts b/packages/client/src/services/app-service.ts index 186e2960..d73cfa60 100644 --- a/packages/client/src/services/app-service.ts +++ b/packages/client/src/services/app-service.ts @@ -85,6 +85,8 @@ export class AppService { this.eventSubscriptionId = eventBus.subscribe((event) => { if (event.type === 'account.deleted') { this.accounts.delete(event.account.id); + } else if (event.type === 'workspace.deleted') { + this.workspaces.delete(event.workspace.userId); } }); } diff --git a/packages/client/src/services/workspaces/workspace-service.ts b/packages/client/src/services/workspaces/workspace-service.ts index 25ca8c37..7b8e4d99 100644 --- a/packages/client/src/services/workspaces/workspace-service.ts +++ b/packages/client/src/services/workspaces/workspace-service.ts @@ -6,6 +6,7 @@ import { workspaceDatabaseMigrations, } from '@colanode/client/databases/workspace'; import { eventBus } from '@colanode/client/lib/event-bus'; +import { mapMetadata } from '@colanode/client/lib/mappers'; import { AccountService } from '@colanode/client/services/accounts/account-service'; import { CollaborationService } from '@colanode/client/services/workspaces/collaboration-service'; import { DocumentService } from '@colanode/client/services/workspaces/document-service'; @@ -161,11 +162,21 @@ export class WorkspaceService { .where('user_id', '=', this.workspace.userId) .execute(); - await this.account.app.database + const deletedMetadata = await this.account.app.database .deleteFrom('metadata') + .returningAll() .where('namespace', '=', this.workspace.userId) .execute(); + if (deletedMetadata.length > 0) { + for (const metadata of deletedMetadata) { + eventBus.publish({ + type: 'metadata.deleted', + metadata: mapMetadata(metadata), + }); + } + } + await this.account.app.jobs.removeJobSchedule( this.workspaceFilesCleanJobScheduleId ); diff --git a/packages/ui/src/collections/index.ts b/packages/ui/src/collections/index.ts index e5142170..e6200719 100644 --- a/packages/ui/src/collections/index.ts +++ b/packages/ui/src/collections/index.ts @@ -1,5 +1,6 @@ import { Collection } from '@tanstack/react-db'; +import { eventBus } from '@colanode/client/lib'; import { Download, LocalNode, @@ -36,6 +37,16 @@ export class WorkspaceCollections { this.nodes = createNodesCollection(userId); this.nodeReactions = createNodeReactionsCollection(userId); } + + public async cleanup(): Promise { + await Promise.all([ + this.users.cleanup(), + this.downloads.cleanup(), + this.uploads.cleanup(), + this.nodes.cleanup(), + this.nodeReactions.cleanup(), + ]); + } } export class AppCollections { @@ -62,6 +73,21 @@ export class AppCollections { } public async preload(): Promise { + eventBus.subscribe((event) => { + if (event.type === 'workspace.deleted') { + try { + const workspaceCollections = this.workspaceCollections.get( + event.workspace.userId + ); + if (workspaceCollections) { + this.workspaceCollections.delete(event.workspace.userId); + } + } catch { + // ignore + } + } + }); + await Promise.all([ this.servers.preload(), this.accounts.preload(), diff --git a/packages/ui/src/components/app/app-provider.tsx b/packages/ui/src/components/app/app-provider.tsx index e9299c50..4a5b3478 100644 --- a/packages/ui/src/components/app/app-provider.tsx +++ b/packages/ui/src/components/app/app-provider.tsx @@ -31,6 +31,7 @@ export const AppProvider = ({ type }: AppProviderProps) => { setInitOutput('success'); }) .catch((err) => { + setInitOutput('error'); console.error('Colanode | Error preloading', err); }); } else {