From f83121ce1d716ffb67ac3afcf91cadc93c8f3bcc Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Wed, 7 Jan 2026 13:48:59 +0200 Subject: [PATCH] chore(core): integrate attachments route --- apps/client/src/lightweight/messaging_provider.ts | 12 ++++++------ apps/server/src/routes/routes.ts | 12 ++---------- .../trilium-core}/src/routes/api/attachments.ts | 3 ++- packages/trilium-core/src/routes/index.ts | 10 ++++++++++ .../trilium-core/src/services/messaging/types.ts | 2 +- packages/trilium-core/src/services/ws.ts | 4 ++-- 6 files changed, 23 insertions(+), 20 deletions(-) rename {apps/server => packages/trilium-core}/src/routes/api/attachments.ts (97%) diff --git a/apps/client/src/lightweight/messaging_provider.ts b/apps/client/src/lightweight/messaging_provider.ts index 28b72c964..4a178fbb0 100644 --- a/apps/client/src/lightweight/messaging_provider.ts +++ b/apps/client/src/lightweight/messaging_provider.ts @@ -3,11 +3,11 @@ import type { MessagingProvider, MessageHandler } from "@triliumnext/core"; /** * Messaging provider for browser Worker environments. - * + * * This provider uses the Worker's postMessage API to communicate * with the main thread. It's designed to be used inside a Web Worker * that runs the core services. - * + * * Message flow: * - Outbound (worker → main): Uses self.postMessage() with type: "WS_MESSAGE" * - Inbound (main → worker): Listens to onmessage for type: "WS_MESSAGE" @@ -24,9 +24,9 @@ export default class WorkerMessagingProvider implements MessagingProvider { private handleIncomingMessage = (event: MessageEvent) => { if (this.isDisposed) return; - + const { type, message } = event.data || {}; - + if (type === "WS_MESSAGE" && message) { // Dispatch to all registered handlers for (const handler of this.messageHandlers) { @@ -64,7 +64,7 @@ export default class WorkerMessagingProvider implements MessagingProvider { */ onMessage(handler: MessageHandler): () => void { this.messageHandlers.push(handler); - + return () => { this.messageHandlers = this.messageHandlers.filter(h => h !== handler); }; @@ -83,7 +83,7 @@ export default class WorkerMessagingProvider implements MessagingProvider { */ dispose(): void { if (this.isDisposed) return; - + this.isDisposed = true; self.removeEventListener("message", this.handleIncomingMessage); this.messageHandlers = []; diff --git a/apps/server/src/routes/routes.ts b/apps/server/src/routes/routes.ts index 64c3d3622..c9efb42f8 100644 --- a/apps/server/src/routes/routes.ts +++ b/apps/server/src/routes/routes.ts @@ -18,7 +18,6 @@ import { isElectron } from "../services/utils.js"; import shareRoutes from "../share/routes.js"; import anthropicRoute from "./api/anthropic.js"; import appInfoRoute from "./api/app_info.js"; -import attachmentsApiRoute from "./api/attachments.js"; import attributesRoute from "./api/attributes.js"; import autocompleteApiRoute from "./api/autocomplete.js"; import backendLogRoute from "./api/backend_log.js"; @@ -135,15 +134,8 @@ function register(app: express.Application) { apiRoute(PUT, "/api/branches/:branchId/set-prefix", branchesApiRoute.setPrefix); apiRoute(PUT, "/api/branches/set-prefix-batch", branchesApiRoute.setPrefixBatch); - apiRoute(GET, "/api/notes/:noteId/attachments", attachmentsApiRoute.getAttachments); - apiRoute(PST, "/api/notes/:noteId/attachments", attachmentsApiRoute.saveAttachment); - route(PST, "/api/notes/:noteId/attachments/upload", [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], attachmentsApiRoute.uploadAttachment, apiResultHandler); - apiRoute(GET, "/api/attachments/:attachmentId", attachmentsApiRoute.getAttachment); - apiRoute(GET, "/api/attachments/:attachmentId/all", attachmentsApiRoute.getAllAttachments); - apiRoute(PST, "/api/attachments/:attachmentId/convert-to-note", attachmentsApiRoute.convertAttachmentToNote); - apiRoute(DEL, "/api/attachments/:attachmentId", attachmentsApiRoute.deleteAttachment); - apiRoute(PUT, "/api/attachments/:attachmentId/rename", attachmentsApiRoute.renameAttachment); - apiRoute(GET, "/api/attachments/:attachmentId/blob", attachmentsApiRoute.getAttachmentBlob); + // TODO: Bring back attachment uploading + // route(PST, "/api/notes/:noteId/attachments/upload", [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], attachmentsApiRoute.uploadAttachment, apiResultHandler); route(GET, "/api/attachments/:attachmentId/image/:filename", [auth.checkApiAuthOrElectron], imageRoute.returnAttachedImage); route(GET, "/api/attachments/:attachmentId/open", [auth.checkApiAuthOrElectron], filesRoute.openAttachment); asyncRoute( diff --git a/apps/server/src/routes/api/attachments.ts b/packages/trilium-core/src/routes/api/attachments.ts similarity index 97% rename from apps/server/src/routes/api/attachments.ts rename to packages/trilium-core/src/routes/api/attachments.ts index 9e409e6f9..eb775dcc1 100644 --- a/apps/server/src/routes/api/attachments.ts +++ b/packages/trilium-core/src/routes/api/attachments.ts @@ -1,5 +1,6 @@ import { ConvertAttachmentToNoteResponse } from "@triliumnext/commons"; -import { blob as blobService, ValidationError } from "@triliumnext/core"; +import blobService from "../../services/blob"; +import { ValidationError } from "../../errors"; import type { Request } from "express"; import becca from "../../becca/becca.js"; diff --git a/packages/trilium-core/src/routes/index.ts b/packages/trilium-core/src/routes/index.ts index 28c80f34a..0d0b11cff 100644 --- a/packages/trilium-core/src/routes/index.ts +++ b/packages/trilium-core/src/routes/index.ts @@ -2,6 +2,7 @@ import optionsApiRoute from "./api/options"; import treeApiRoute from "./api/tree"; import keysApiRoute from "./api/keys"; import notesApiRoute from "./api/notes"; +import attachmentsApiRoute from "./api/attachments"; import AbstractBeccaEntity from "../becca/entities/abstract_becca_entity"; // TODO: Deduplicate with routes.ts @@ -40,6 +41,15 @@ export function buildSharedApiRoutes(apiRoute: any) { apiRoute(PST, "/api/notes/erase-unused-attachments-now", notesApiRoute.eraseUnusedAttachmentsNow); apiRoute(PST, "/api/delete-notes-preview", notesApiRoute.getDeleteNotesPreview); + apiRoute(GET, "/api/notes/:noteId/attachments", attachmentsApiRoute.getAttachments); + apiRoute(PST, "/api/notes/:noteId/attachments", attachmentsApiRoute.saveAttachment); + apiRoute(GET, "/api/attachments/:attachmentId", attachmentsApiRoute.getAttachment); + apiRoute(GET, "/api/attachments/:attachmentId/all", attachmentsApiRoute.getAllAttachments); + apiRoute(PST, "/api/attachments/:attachmentId/convert-to-note", attachmentsApiRoute.convertAttachmentToNote); + apiRoute(DEL, "/api/attachments/:attachmentId", attachmentsApiRoute.deleteAttachment); + apiRoute(PUT, "/api/attachments/:attachmentId/rename", attachmentsApiRoute.renameAttachment); + apiRoute(GET, "/api/attachments/:attachmentId/blob", attachmentsApiRoute.getAttachmentBlob); + apiRoute(GET, "/api/keyboard-actions", keysApiRoute.getKeyboardActions); apiRoute(GET, "/api/keyboard-shortcuts-for-notes", keysApiRoute.getShortcutsForNotes); } diff --git a/packages/trilium-core/src/services/messaging/types.ts b/packages/trilium-core/src/services/messaging/types.ts index ae02ae061..655df6736 100644 --- a/packages/trilium-core/src/services/messaging/types.ts +++ b/packages/trilium-core/src/services/messaging/types.ts @@ -19,7 +19,7 @@ export interface MessageClient { /** * Provider interface for server-to-client messaging. - * + * * This abstraction allows different transport mechanisms: * - WebSocket for traditional server environments * - Worker postMessage for browser environments diff --git a/packages/trilium-core/src/services/ws.ts b/packages/trilium-core/src/services/ws.ts index 9e390a03e..01e2efb6d 100644 --- a/packages/trilium-core/src/services/ws.ts +++ b/packages/trilium-core/src/services/ws.ts @@ -3,11 +3,11 @@ import { sendMessageToAllClients as sendMessage } from "./messaging/index.js"; /** * WebSocket service abstraction for core. - * + * * This module provides a simple interface for sending messages to clients. * The actual transport mechanism is provided by the messaging provider * configured during initialization. - * + * * @deprecated Use the messaging module directly instead. */ export default {