From f9a3606ca2aa1dde53eb5dfbc3548ed02aea348f Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 17:11:54 +0000 Subject: [PATCH 1/4] feat(docs): implement swagger ui endpoint for internal api --- apps/server/src/assets/api-openapi.yaml | 4112 +++++++++++++++++++++++ apps/server/src/routes/api_docs.ts | 17 +- 2 files changed, 4126 insertions(+), 3 deletions(-) create mode 100644 apps/server/src/assets/api-openapi.yaml diff --git a/apps/server/src/assets/api-openapi.yaml b/apps/server/src/assets/api-openapi.yaml new file mode 100644 index 000000000..f8b5ebf81 --- /dev/null +++ b/apps/server/src/assets/api-openapi.yaml @@ -0,0 +1,4112 @@ +openapi: 3.1.0 +info: + title: Trilium Notes Internal API + version: 0.94.0 + description: | + This is the internal API used by the Trilium Notes client application. + + **Important:** This API is primarily intended for internal use by the Trilium client. + For external integrations, please use the [ETAPI (External Trilium API)](https://triliumnext.github.io/Docs/Wiki/etapi.html) instead. + + ## Authentication + + Most endpoints require session-based authentication. You can authenticate using: + - **Password login**: POST to `/api/login` with password + - **Token authentication**: Generate a token via `/api/login/token` + - **Sync authentication**: Use document secret for sync operations + + ## Rate Limiting + + Authentication endpoints are rate-limited to prevent brute force attacks. + + ## CSRF Protection + + State-changing operations require CSRF tokens when using session authentication. + + contact: + name: TriliumNext Issue Tracker + url: https://github.com/TriliumNext/Notes/issues + license: + name: GNU Affero General Public License v3.0 + url: https://www.gnu.org/licenses/agpl-3.0.html + +servers: + - url: http://localhost:8080 + description: Default local server + - url: https://your-trilium-server.com + description: Your Trilium server + +tags: + - name: Authentication + description: Login, logout, and session management + - name: Notes + description: Core note operations + - name: Tree + description: Note tree structure and branches + - name: Attributes + description: Note attributes and metadata + - name: Attachments + description: File attachments + - name: Revisions + description: Note revision history + - name: Search + description: Search and discovery + - name: Import/Export + description: Import and export operations + - name: Sync + description: Synchronization between instances + - name: Scripting + description: Script execution and automation + - name: Configuration + description: System options and settings + - name: Database + description: Database operations + - name: LLM + description: AI/LLM integration + - name: Security + description: Security features (2FA, tokens) + - name: Special Notes + description: Special note types (calendar, inbox) + - name: Visualization + description: Maps and visualizations + - name: External + description: External integrations (clipper, sender) + - name: Utilities + description: Miscellaneous utilities + +security: + - sessionAuth: [] + - tokenAuth: [] + +paths: + # Authentication endpoints + /api/login: + post: + tags: [Authentication] + summary: Login with password + operationId: login + security: [] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + totpToken: + type: string + description: TOTP token if 2FA is enabled + responses: + '200': + description: Login successful + headers: + Set-Cookie: + schema: + type: string + example: trilium.sid=s%3A... + '401': + description: Invalid credentials or TOTP token + + /api/login/token: + post: + tags: [Authentication] + summary: Generate API token + operationId: generateToken + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + tokenName: + type: string + description: Optional name for the token + responses: + '201': + description: Token created + content: + application/json: + schema: + type: object + properties: + authToken: + type: string + description: API authentication token + + /api/login/sync: + post: + tags: [Authentication, Sync] + summary: Sync login using document secret + operationId: loginSync + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [timestamp, hash, syncVersion] + properties: + timestamp: + type: string + format: date-time + hash: + type: string + description: HMAC hash of document secret and timestamp + syncVersion: + type: integer + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + instanceId: + type: string + maxEntityChangeId: + type: string + + /api/login/protected: + post: + tags: [Authentication, Security] + summary: Enter protected session + operationId: enterProtectedSession + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + responses: + '200': + description: Protected session entered + '401': + description: Invalid password + + /api/logout/protected: + post: + tags: [Authentication, Security] + summary: Exit protected session + operationId: exitProtectedSession + responses: + '204': + description: Protected session exited + + /api/login/protected/touch: + post: + tags: [Authentication, Security] + summary: Keep protected session alive + operationId: touchProtectedSession + responses: + '204': + description: Session refreshed + + # App Info + /api/app-info: + get: + tags: [Configuration] + summary: Get application information + operationId: getAppInfo + responses: + '200': + description: Application information + content: + application/json: + schema: + $ref: '#/components/schemas/AppInfo' + + # Setup endpoints + /api/setup/status: + get: + tags: [Configuration] + summary: Get setup status + operationId: getSetupStatus + security: [] + responses: + '200': + description: Setup status + content: + application/json: + schema: + type: object + properties: + isInitialized: + type: boolean + schemaExists: + type: boolean + syncVersion: + type: integer + + /api/setup/new-document: + post: + tags: [Configuration] + summary: Initialize new document + operationId: initNewDocument + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + theme: + type: string + responses: + '201': + description: Document initialized + + /api/setup/sync-from-server: + post: + tags: [Configuration, Sync] + summary: Setup sync from server + operationId: setupSyncFromServer + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [syncServerHost, password] + properties: + syncServerHost: + type: string + format: uri + syncProxy: + type: string + password: + type: string + format: password + responses: + '200': + description: Sync setup successful + + # Note operations + /api/notes/{noteId}: + get: + tags: [Notes] + summary: Get note metadata + operationId: getNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note metadata + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + '404': + description: Note not found + + delete: + tags: [Notes] + summary: Delete note + operationId: deleteNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: taskId + in: query + required: true + schema: + type: string + - name: eraseNotes + in: query + schema: + type: boolean + default: false + - name: last + in: query + required: true + schema: + type: boolean + responses: + '204': + description: Note deleted + '404': + description: Note not found + + /api/notes/{noteId}/blob: + get: + tags: [Notes] + summary: Get note content + operationId: getNoteContent + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note content + content: + text/html: + schema: + type: string + text/plain: + schema: + type: string + application/json: + schema: + type: object + application/octet-stream: + schema: + type: string + format: binary + '404': + description: Note not found + + /api/notes/{noteId}/data: + put: + tags: [Notes] + summary: Update note content + operationId: updateNoteContent + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [content] + properties: + content: + type: string + attachments: + type: array + items: + $ref: '#/components/schemas/Attachment' + responses: + '204': + description: Content updated + '404': + description: Note not found + + /api/notes/{noteId}/metadata: + get: + tags: [Notes] + summary: Get note timestamps + operationId: getNoteMetadata + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note timestamps + content: + application/json: + schema: + $ref: '#/components/schemas/Timestamps' + '404': + description: Note not found + + /api/notes/{noteId}/title: + put: + tags: [Notes] + summary: Change note title + operationId: updateNoteTitle + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [title] + properties: + title: + type: string + responses: + '204': + description: Title updated + '404': + description: Note not found + + /api/notes/{noteId}/type: + put: + tags: [Notes] + summary: Change note type and MIME + operationId: updateNoteType + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [type, mime] + properties: + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + responses: + '204': + description: Type updated + '404': + description: Note not found + + /api/notes/{noteId}/protect/{isProtected}: + put: + tags: [Notes, Security] + summary: Protect or unprotect note + operationId: protectNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: isProtected + in: path + required: true + schema: + type: boolean + - name: subtree + in: query + schema: + type: boolean + default: false + responses: + '204': + description: Protection status updated + '404': + description: Note not found + + /api/notes/{noteId}/undelete: + put: + tags: [Notes] + summary: Undelete note + operationId: undeleteNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '204': + description: Note undeleted + '404': + description: Note not found + + /api/notes/{parentNoteId}/children: + post: + tags: [Notes, Tree] + summary: Create new note + operationId: createNote + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: target + in: query + schema: + type: string + enum: [after, into] + - name: targetBranchId + in: query + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateNoteRequest' + responses: + '201': + description: Note created + content: + application/json: + schema: + type: object + properties: + note: + $ref: '#/components/schemas/Note' + branch: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/duplicate/{parentNoteId}: + post: + tags: [Notes, Tree] + summary: Duplicate note subtree + operationId: duplicateNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + responses: + '201': + description: Note duplicated + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/notes/{noteId}/revision: + post: + tags: [Notes, Revisions] + summary: Force save revision + operationId: saveRevision + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '201': + description: Revision saved + content: + application/json: + schema: + $ref: '#/components/schemas/Revision' + + /api/notes/{noteId}/sort-children: + put: + tags: [Notes, Tree] + summary: Sort child notes + operationId: sortChildren + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + sortBy: + type: string + enum: [title, dateCreated, dateModified] + sortDirection: + type: string + enum: [asc, desc] + foldersFirst: + type: boolean + sortNatural: + type: boolean + sortLocale: + type: string + responses: + '204': + description: Children sorted + + /api/notes/{noteId}/convert-to-attachment: + post: + tags: [Notes, Attachments] + summary: Convert note to attachment + operationId: convertToAttachment + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note converted to attachment + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + # File operations + /api/notes/{noteId}/file: + put: + tags: [Notes] + summary: Upload file to note + operationId: uploadFileToNote + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: File uploaded + + /api/notes/{noteId}/open: + get: + tags: [Notes] + summary: Open file note + operationId: openFileNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/download: + get: + tags: [Notes] + summary: Download file note + operationId: downloadFileNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/open-partial: + get: + tags: [Notes] + summary: Stream file with partial content support + operationId: openPartialFileNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: Range + in: header + schema: + type: string + example: bytes=0-1023 + responses: + '206': + description: Partial content + headers: + Content-Range: + schema: + type: string + example: bytes 0-1023/146515 + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/save-to-tmp-dir: + post: + tags: [Notes] + summary: Save note to temp directory + operationId: saveToTmpDir + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File saved to temp directory + content: + application/json: + schema: + type: object + properties: + filePath: + type: string + + /api/notes/{noteId}/upload-modified-file: + post: + tags: [Notes] + summary: Update note from modified temp file + operationId: uploadModifiedFile + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [filePath] + properties: + filePath: + type: string + responses: + '204': + description: Note updated from file + + # Tree and branch operations + /api/tree: + get: + tags: [Tree] + summary: Get tree structure + operationId: getTree + parameters: + - name: subTreeNoteId + in: query + schema: + type: string + description: Limit tree to this note and descendants + responses: + '200': + description: Tree structure + content: + application/json: + schema: + type: object + properties: + notes: + type: array + items: + $ref: '#/components/schemas/Note' + branches: + type: array + items: + $ref: '#/components/schemas/Branch' + attributes: + type: array + items: + $ref: '#/components/schemas/Attribute' + + /api/tree/load: + post: + tags: [Tree] + summary: Load specific notes + operationId: loadNotes + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [noteIds] + properties: + noteIds: + type: array + items: + type: string + responses: + '200': + description: Loaded notes + content: + application/json: + schema: + type: object + properties: + notes: + type: array + items: + $ref: '#/components/schemas/Note' + branches: + type: array + items: + $ref: '#/components/schemas/Branch' + attributes: + type: array + items: + $ref: '#/components/schemas/Attribute' + + /api/branches/{branchId}: + delete: + tags: [Tree] + summary: Delete branch + operationId: deleteBranch + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: taskId + in: query + required: true + schema: + type: string + - name: eraseNotes + in: query + schema: + type: boolean + - name: last + in: query + required: true + schema: + type: boolean + responses: + '200': + description: Branch deleted + content: + application/json: + schema: + type: object + properties: + noteDeleted: + type: boolean + + /api/branches/{branchId}/move-to/{parentBranchId}: + put: + tags: [Tree] + summary: Move branch to new parent + operationId: moveBranchToParent + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: parentBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/move-before/{beforeBranchId}: + put: + tags: [Tree] + summary: Move branch before another + operationId: moveBranchBefore + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: beforeBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/move-after/{afterBranchId}: + put: + tags: [Tree] + summary: Move branch after another + operationId: moveBranchAfter + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: afterBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/expanded/{expanded}: + put: + tags: [Tree] + summary: Set branch expanded state + operationId: setBranchExpanded + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: expanded + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Expanded state updated + + /api/branches/{branchId}/expanded-subtree/{expanded}: + put: + tags: [Tree] + summary: Set subtree expanded state + operationId: setSubtreeExpanded + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: expanded + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Subtree expanded state updated + + /api/branches/{branchId}/set-prefix: + put: + tags: [Tree] + summary: Set branch prefix + operationId: setBranchPrefix + parameters: + - name: branchId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + prefix: + type: string + nullable: true + responses: + '204': + description: Prefix updated + + # Cloning operations + /api/notes/{noteId}/clone-to-branch/{parentBranchId}: + put: + tags: [Tree, Notes] + summary: Clone note to branch + operationId: cloneToBranch + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentBranchId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/clone-to-note/{parentNoteId}: + put: + tags: [Tree, Notes] + summary: Clone note to parent note + operationId: cloneToNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/clone-after/{afterBranchId}: + put: + tags: [Tree, Notes] + summary: Clone note after branch + operationId: cloneAfterBranch + parameters: + - $ref: '#/components/parameters/noteId' + - name: afterBranchId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/toggle-in-parent/{parentNoteId}/{present}: + put: + tags: [Tree, Notes] + summary: Toggle note presence in parent + operationId: toggleInParent + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: present + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Presence toggled + + # Attributes + /api/notes/{noteId}/attributes: + get: + tags: [Attributes] + summary: Get effective note attributes + operationId: getNoteAttributes + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note attributes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attribute' + + post: + tags: [Attributes] + summary: Add note attribute + operationId: addNoteAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '201': + description: Attribute added + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + + put: + tags: [Attributes] + summary: Update all note attributes + operationId: updateNoteAttributes + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attribute' + responses: + '204': + description: Attributes updated + + /api/notes/{noteId}/attributes/{attributeId}: + delete: + tags: [Attributes] + summary: Delete attribute + operationId: deleteAttribute + parameters: + - $ref: '#/components/parameters/noteId' + - name: attributeId + in: path + required: true + schema: + type: string + responses: + '204': + description: Attribute deleted + + /api/notes/{noteId}/attribute: + put: + tags: [Attributes] + summary: Update single attribute + operationId: updateAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '204': + description: Attribute updated + + /api/notes/{noteId}/set-attribute: + put: + tags: [Attributes] + summary: Set attribute value + operationId: setAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [type, name, value] + properties: + type: + type: string + enum: [label, relation] + name: + type: string + value: + type: string + responses: + '204': + description: Attribute set + + /api/notes/{noteId}/relations/{name}/to/{targetNoteId}: + put: + tags: [Attributes] + summary: Create relation + operationId: createRelation + parameters: + - $ref: '#/components/parameters/noteId' + - name: name + in: path + required: true + schema: + type: string + - name: targetNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Relation created + + delete: + tags: [Attributes] + summary: Delete relation + operationId: deleteRelation + parameters: + - $ref: '#/components/parameters/noteId' + - name: name + in: path + required: true + schema: + type: string + - name: targetNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Relation deleted + + /api/attribute-names: + get: + tags: [Attributes] + summary: Get attribute name suggestions + operationId: getAttributeNames + parameters: + - name: type + in: query + required: true + schema: + type: string + enum: [label, relation] + - name: query + in: query + schema: + type: string + responses: + '200': + description: Attribute names + content: + application/json: + schema: + type: array + items: + type: string + + /api/attribute-values/{attributeName}: + get: + tags: [Attributes] + summary: Get values for attribute + operationId: getAttributeValues + parameters: + - name: attributeName + in: path + required: true + schema: + type: string + responses: + '200': + description: Attribute values + content: + application/json: + schema: + type: array + items: + type: string + + # Attachments + /api/notes/{noteId}/attachments: + get: + tags: [Attachments] + summary: Get note attachments + operationId: getNoteAttachments + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note attachments + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attachment' + + post: + tags: [Attachments] + summary: Save attachment + operationId: saveAttachment + parameters: + - $ref: '#/components/parameters/noteId' + - name: matchBy + in: query + schema: + type: string + enum: [attachmentId, title] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + responses: + '201': + description: Attachment saved + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + /api/notes/{noteId}/attachments/upload: + post: + tags: [Attachments] + summary: Upload attachment file + operationId: uploadAttachment + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '201': + description: Attachment uploaded + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + /api/attachments/{attachmentId}: + get: + tags: [Attachments] + summary: Get attachment metadata + operationId: getAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment metadata + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + delete: + tags: [Attachments] + summary: Delete attachment + operationId: deleteAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '204': + description: Attachment deleted + + /api/attachments/{attachmentId}/blob: + get: + tags: [Attachments] + summary: Get attachment content + operationId: getAttachmentBlob + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + - name: preview + in: query + schema: + type: boolean + responses: + '200': + description: Attachment content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/rename: + put: + tags: [Attachments] + summary: Rename attachment + operationId: renameAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [title] + properties: + title: + type: string + responses: + '204': + description: Attachment renamed + + /api/attachments/{attachmentId}/convert-to-note: + post: + tags: [Attachments, Notes] + summary: Convert attachment to note + operationId: convertAttachmentToNote + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment converted to note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/attachments/{attachmentId}/file: + put: + tags: [Attachments] + summary: Update attachment file + operationId: updateAttachmentFile + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: Attachment file updated + + /api/attachments/{attachmentId}/open: + get: + tags: [Attachments] + summary: Open attachment + operationId: openAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/download: + get: + tags: [Attachments] + summary: Download attachment + operationId: downloadAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + # Revisions + /api/notes/{noteId}/revisions: + get: + tags: [Revisions] + summary: Get note revisions + operationId: getNoteRevisions + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note revisions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Revision' + + delete: + tags: [Revisions] + summary: Erase all note revisions + operationId: eraseNoteRevisions + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '204': + description: Revisions erased + + /api/revisions/{revisionId}: + get: + tags: [Revisions] + summary: Get revision details + operationId: getRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision details + content: + application/json: + schema: + $ref: '#/components/schemas/Revision' + + delete: + tags: [Revisions] + summary: Erase revision + operationId: eraseRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '204': + description: Revision erased + + /api/revisions/{revisionId}/blob: + get: + tags: [Revisions] + summary: Get revision content + operationId: getRevisionBlob + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + - name: preview + in: query + schema: + type: boolean + responses: + '200': + description: Revision content + content: + text/html: + schema: + type: string + text/plain: + schema: + type: string + application/octet-stream: + schema: + type: string + format: binary + + /api/revisions/{revisionId}/restore: + post: + tags: [Revisions, Notes] + summary: Restore revision + operationId: restoreRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision restored + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/revisions/{revisionId}/download: + get: + tags: [Revisions] + summary: Download revision + operationId: downloadRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision content + headers: + Content-Disposition: + schema: + type: string + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/revisions/erase-all-excess-revisions: + post: + tags: [Revisions] + summary: Cleanup old revisions + operationId: eraseExcessRevisions + responses: + '204': + description: Excess revisions erased + + /api/edited-notes/{date}: + get: + tags: [Revisions] + summary: Get notes edited on date + operationId: getEditedNotes + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + example: '2024-01-15' + responses: + '200': + description: Edited notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + # Search + /api/search/{searchString}: + get: + tags: [Search] + summary: Full text search + operationId: search + parameters: + - name: searchString + in: path + required: true + schema: + type: string + responses: + '200': + description: Search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/quick-search/{searchString}: + get: + tags: [Search] + summary: Quick search with highlighting + operationId: quickSearch + parameters: + - name: searchString + in: path + required: true + schema: + type: string + responses: + '200': + description: Quick search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/search-note/{noteId}: + get: + tags: [Search] + summary: Execute search note + operationId: executeSearchNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/search-and-execute-note/{noteId}: + post: + tags: [Search, Scripting] + summary: Search and execute actions + operationId: searchAndExecute + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Execution results + + /api/search-related: + post: + tags: [Search] + summary: Find related notes by attributes + operationId: searchRelated + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '200': + description: Related notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + /api/search-templates: + get: + tags: [Search] + summary: Search template notes + operationId: searchTemplates + responses: + '200': + description: Template notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + /api/autocomplete: + get: + tags: [Search] + summary: Get autocomplete suggestions + operationId: autocomplete + parameters: + - name: query + in: query + required: true + schema: + type: string + - name: fastSearch + in: query + schema: + type: boolean + - name: activeNoteId + in: query + schema: + type: string + responses: + '200': + description: Autocomplete suggestions + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + path: + type: string + + /api/autocomplete/notesCount: + get: + tags: [Search] + summary: Get total notes count + operationId: getNotesCount + responses: + '200': + description: Notes count + content: + application/json: + schema: + type: object + properties: + count: + type: integer + + /api/similar-notes/{noteId}: + get: + tags: [Search] + summary: Find similar notes + operationId: findSimilarNotes + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Similar notes + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + similarity: + type: number + + # Images + /api/images/{noteId}/{filename}: + get: + tags: [Notes] + summary: Get image from note + operationId: getNoteImage + parameters: + - $ref: '#/components/parameters/noteId' + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + /api/images/{noteId}: + put: + tags: [Notes] + summary: Update image note + operationId: updateImageNote + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: Image updated + + /api/attachments/{attachmentId}/image/{filename}: + get: + tags: [Attachments] + summary: Get attached image + operationId: getAttachmentImage + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + /api/revisions/{revisionId}/image/{filename}: + get: + tags: [Revisions] + summary: Get image from revision + operationId: getRevisionImage + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + # Import/Export + /api/branches/{branchId}/export/{type}/{format}/{version}/{taskId}: + get: + tags: [Import/Export] + summary: Export branch + operationId: exportBranch + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: type + in: path + required: true + schema: + type: string + enum: [subtree, single] + - name: format + in: path + required: true + schema: + type: string + enum: [html, markdown, opml] + - name: version + in: path + required: true + schema: + type: string + - name: taskId + in: path + required: true + schema: + type: string + responses: + '200': + description: Exported content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{parentNoteId}/notes-import: + post: + tags: [Import/Export] + summary: Import notes + operationId: importNotes + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + safeImport: + type: boolean + shrinkImages: + type: boolean + textImportedAsText: + type: boolean + codeImportedAsCode: + type: boolean + explodeArchives: + type: boolean + replaceUnderscoresWithSpaces: + type: boolean + responses: + '200': + description: Import results + content: + application/json: + schema: + type: object + properties: + noteId: + type: string + note: + $ref: '#/components/schemas/Note' + + /api/notes/{parentNoteId}/attachments-import: + post: + tags: [Import/Export, Attachments] + summary: Import attachments + operationId: importAttachments + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: array + items: + type: string + format: binary + responses: + '200': + description: Import results + + # Options + /api/options: + get: + tags: [Configuration] + summary: Get system options + operationId: getOptions + responses: + '200': + description: System options + content: + application/json: + schema: + type: object + additionalProperties: + type: string + + put: + tags: [Configuration] + summary: Update multiple options + operationId: updateOptions + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: + type: string + responses: + '204': + description: Options updated + + /api/options/{name}/{value}: + put: + tags: [Configuration] + summary: Update single option + operationId: updateOption + parameters: + - name: name + in: path + required: true + schema: + type: string + - name: value + in: path + required: true + schema: + type: string + responses: + '204': + description: Option updated + + /api/options/user-themes: + get: + tags: [Configuration] + summary: Get user-defined themes + operationId: getUserThemes + responses: + '200': + description: User themes + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + label: + type: string + + /api/options/locales: + get: + tags: [Configuration] + summary: Get supported locales + operationId: getLocales + responses: + '200': + description: Supported locales + content: + application/json: + schema: + type: array + items: + type: object + properties: + code: + type: string + name: + type: string + + # Password management + /api/password/change: + post: + tags: [Security] + summary: Change password + operationId: changePassword + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [new_password] + properties: + current_password: + type: string + format: password + new_password: + type: string + format: password + responses: + '204': + description: Password changed + + /api/password/reset: + post: + tags: [Security] + summary: Reset password (destructive) + operationId: resetPassword + parameters: + - name: really + in: query + required: true + schema: + type: string + example: yesIReallyWantToResetMyPassword + responses: + '204': + description: Password reset + + # Sync + /api/sync/test: + post: + tags: [Sync] + summary: Test sync connection + operationId: testSync + responses: + '200': + description: Sync test results + + /api/sync/now: + post: + tags: [Sync] + summary: Trigger sync now + operationId: syncNow + responses: + '200': + description: Sync started + + /api/sync/check: + get: + tags: [Sync] + summary: Get sync status + operationId: checkSync + responses: + '200': + description: Sync status + content: + application/json: + schema: + type: object + properties: + synced: + type: boolean + lastSyncedPush: + type: string + format: date-time + lastSyncedPull: + type: string + format: date-time + + /api/sync/changed: + get: + tags: [Sync] + summary: Get sync changes + operationId: getSyncChanges + parameters: + - name: instanceId + in: query + required: true + schema: + type: string + - name: lastEntityChangeId + in: query + required: true + schema: + type: integer + - name: logMarkerId + in: query + required: true + schema: + type: string + responses: + '200': + description: Sync changes + content: + application/json: + schema: + type: object + properties: + entityChanges: + type: array + items: + $ref: '#/components/schemas/EntityChange' + lastEntityChangeId: + type: integer + outstandingPullCount: + type: integer + + /api/sync/update: + put: + tags: [Sync] + summary: Push sync changes + operationId: pushSyncChanges + parameters: + - name: logMarkerId + in: query + required: true + schema: + type: string + - name: pageCount + in: header + required: true + schema: + type: integer + - name: pageIndex + in: header + required: true + schema: + type: integer + - name: requestId + in: header + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + instanceId: + type: string + entities: + type: array + items: + $ref: '#/components/schemas/EntityChange' + responses: + '200': + description: Changes processed + + /api/sync/finished: + post: + tags: [Sync] + summary: Mark sync as finished + operationId: finishSync + responses: + '204': + description: Sync finished + + /api/sync/stats: + get: + tags: [Sync] + summary: Get sync statistics + operationId: getSyncStats + security: [] + responses: + '200': + description: Sync statistics + content: + application/json: + schema: + type: object + properties: + initialized: + type: boolean + stats: + type: object + + /api/sync/fill-entity-changes: + post: + tags: [Sync] + summary: Fill entity changes + operationId: fillEntityChanges + responses: + '204': + description: Entity changes filled + + /api/sync/force-full-sync: + post: + tags: [Sync] + summary: Force full sync + operationId: forceFullSync + responses: + '204': + description: Full sync forced + + /api/sync/check-entity-changes: + post: + tags: [Sync] + summary: Check entity changes consistency + operationId: checkEntityChanges + responses: + '200': + description: Consistency check results + + /api/sync/queue-sector/{entityName}/{sector}: + post: + tags: [Sync] + summary: Queue sector for sync + operationId: queueSyncSector + parameters: + - name: entityName + in: path + required: true + schema: + type: string + - name: sector + in: path + required: true + schema: + type: string + responses: + '204': + description: Sector queued + + # Scripting + /api/script/exec: + post: + tags: [Scripting] + summary: Execute script + operationId: executeScript + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [script] + properties: + script: + type: string + params: + type: array + items: + type: string + startNoteId: + type: string + currentNoteId: + type: string + originEntityName: + type: string + originEntityId: + type: string + transactional: + type: boolean + responses: + '200': + description: Script execution results + content: + application/json: + schema: + type: object + + /api/script/run/{noteId}: + post: + tags: [Scripting] + summary: Run script note + operationId: runScriptNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Script execution results + + /api/script/startup: + get: + tags: [Scripting] + summary: Get startup script bundles + operationId: getStartupScripts + parameters: + - name: mobile + in: query + schema: + type: boolean + responses: + '200': + description: Startup scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/widgets: + get: + tags: [Scripting] + summary: Get widget script bundles + operationId: getWidgetScripts + responses: + '200': + description: Widget scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/bundle/{noteId}: + post: + tags: [Scripting] + summary: Get script bundle for note + operationId: getScriptBundle + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Script bundle + content: + application/json: + schema: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/relation/{noteId}/{relationName}: + get: + tags: [Scripting] + summary: Get relation script bundles + operationId: getRelationScripts + parameters: + - $ref: '#/components/parameters/noteId' + - name: relationName + in: path + required: true + schema: + type: string + responses: + '200': + description: Relation scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + # Database + /api/sql/schema: + get: + tags: [Database] + summary: Get database schema + operationId: getDatabaseSchema + responses: + '200': + description: Database schema + content: + text/plain: + schema: + type: string + + /api/sql/execute/{noteId}: + post: + tags: [Database] + summary: Execute SQL from note + operationId: executeSql + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: SQL execution results + content: + application/json: + schema: + type: array + items: + type: object + + /api/database/backup-database: + post: + tags: [Database] + summary: Create database backup + operationId: backupDatabase + responses: + '204': + description: Backup created + + /api/database/backups: + get: + tags: [Database] + summary: List existing backups + operationId: listBackups + responses: + '200': + description: Backup list + content: + application/json: + schema: + type: array + items: + type: string + + /api/database/vacuum-database: + post: + tags: [Database] + summary: Vacuum database + operationId: vacuumDatabase + responses: + '204': + description: Database vacuumed + + /api/database/anonymize/{type}: + post: + tags: [Database] + summary: Anonymize database + operationId: anonymizeDatabase + parameters: + - name: type + in: path + required: true + schema: + type: string + enum: [save-as-file, save-and-send] + responses: + '200': + description: Anonymization results + + /api/database/anonymized-databases: + get: + tags: [Database] + summary: List anonymized databases + operationId: listAnonymizedDatabases + responses: + '200': + description: Anonymized database list + content: + application/json: + schema: + type: array + items: + type: string + + /api/database/find-and-fix-consistency-issues: + post: + tags: [Database] + summary: Fix consistency issues + operationId: fixConsistencyIssues + responses: + '200': + description: Consistency check results + + /api/database/check-integrity: + get: + tags: [Database] + summary: Check database integrity + operationId: checkIntegrity + responses: + '200': + description: Integrity check results + content: + application/json: + schema: + type: object + properties: + results: + type: array + items: + type: string + + # System + /api/metrics: + get: + tags: [Utilities] + summary: Get system metrics + operationId: getMetrics + parameters: + - name: format + in: query + schema: + type: string + enum: [prometheus, json] + default: json + responses: + '200': + description: System metrics + content: + application/json: + schema: + type: object + text/plain: + schema: + type: string + + /api/system-checks: + get: + tags: [Utilities] + summary: Run system diagnostics + operationId: runSystemChecks + responses: + '200': + description: System check results + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + status: + type: string + enum: [pass, fail] + message: + type: string + + /api/health-check: + get: + tags: [Utilities] + summary: Health check endpoint + operationId: healthCheck + security: [] + responses: + '200': + description: Service is healthy + content: + text/plain: + schema: + type: string + example: OK + + /api/backend-log: + get: + tags: [Utilities] + summary: Get backend log + operationId: getBackendLog + responses: + '200': + description: Backend log entries + content: + application/json: + schema: + type: array + items: + type: object + properties: + timestamp: + type: string + format: date-time + level: + type: string + message: + type: string + + # Bulk operations + /api/bulk-action/execute: + post: + tags: [Notes] + summary: Execute bulk action + operationId: executeBulkAction + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + noteIds: + type: array + items: + type: string + responses: + '200': + description: Bulk action results + + /api/bulk-action/affected-notes: + post: + tags: [Notes] + summary: Get affected notes count + operationId: getAffectedNotesCount + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + noteIds: + type: array + items: + type: string + responses: + '200': + description: Affected notes count + content: + application/json: + schema: + type: object + properties: + count: + type: integer + + /api/delete-notes-preview: + post: + tags: [Notes] + summary: Preview note deletion + operationId: previewNoteDeletion + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + branchIdsToDelete: + type: array + items: + type: string + deleteAllClones: + type: boolean + responses: + '200': + description: Deletion preview + content: + application/json: + schema: + type: object + properties: + notesToDelete: + type: array + items: + type: string + + /api/notes/erase-deleted-notes-now: + post: + tags: [Notes] + summary: Erase deleted notes + operationId: eraseDeletedNotes + responses: + '204': + description: Deleted notes erased + + /api/notes/erase-unused-attachments-now: + post: + tags: [Attachments] + summary: Erase unused attachments + operationId: eraseUnusedAttachments + responses: + '204': + description: Unused attachments erased + + # Special notes + /api/special-notes/inbox/{date}: + get: + tags: [Special Notes] + summary: Get/create inbox note + operationId: getInboxNote + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + responses: + '200': + description: Inbox note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/days/{date}: + get: + tags: [Special Notes] + summary: Get/create day note + operationId: getDayNote + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + responses: + '200': + description: Day note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/weeks/{week}: + get: + tags: [Special Notes] + summary: Get/create week note + operationId: getWeekNote + parameters: + - name: week + in: path + required: true + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: '2024-03' + responses: + '200': + description: Week note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/months/{month}: + get: + tags: [Special Notes] + summary: Get/create month note + operationId: getMonthNote + parameters: + - name: month + in: path + required: true + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: '2024-01' + responses: + '200': + description: Month note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/years/{year}: + get: + tags: [Special Notes] + summary: Get/create year note + operationId: getYearNote + parameters: + - name: year + in: path + required: true + schema: + type: string + pattern: ^\d{4}$ + example: '2024' + responses: + '200': + description: Year note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/sql-console: + post: + tags: [Special Notes, Database] + summary: Create SQL console note + operationId: createSqlConsole + responses: + '201': + description: SQL console created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/search-note: + post: + tags: [Special Notes, Search] + summary: Create search note + operationId: createSearchNote + responses: + '201': + description: Search note created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/launchers/{parentNoteId}/{launcherType}: + post: + tags: [Special Notes] + summary: Create launcher + operationId: createLauncher + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: launcherType + in: path + required: true + schema: + type: string + responses: + '201': + description: Launcher created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + # Maps + /api/note-map/{noteId}/tree: + post: + tags: [Visualization] + summary: Get tree map + operationId: getTreeMap + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Tree map data + content: + application/json: + schema: + type: object + + /api/note-map/{noteId}/link: + post: + tags: [Visualization] + summary: Get link map + operationId: getLinkMap + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Link map data + content: + application/json: + schema: + type: object + + /api/note-map/{noteId}/backlinks: + get: + tags: [Visualization] + summary: Get backlinks + operationId: getBacklinks + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Backlinks + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + + /api/relation-map: + post: + tags: [Visualization] + summary: Get relation map data + operationId: getRelationMap + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + noteId: + type: string + maxDepth: + type: integer + excludeArchived: + type: boolean + responses: + '200': + description: Relation map data + content: + application/json: + schema: + type: object + + # External integrations + /api/clipper/handshake: + get: + tags: [External] + summary: Clipper handshake + operationId: clipperHandshake + responses: + '200': + description: Handshake successful + content: + application/json: + schema: + type: object + properties: + protocolVersion: + type: string + + /api/clipper/clippings: + post: + tags: [External] + summary: Add web clipping + operationId: addClipping + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + url: + type: string + responses: + '201': + description: Clipping created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/clipper/notes: + post: + tags: [External] + summary: Create clipper note + operationId: createClipperNote + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + parentNoteId: + type: string + responses: + '201': + description: Note created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/sender/login: + post: + tags: [External] + summary: Sender login + operationId: senderLogin + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [username, password] + properties: + username: + type: string + password: + type: string + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + token: + type: string + + /api/sender/image: + post: + tags: [External] + summary: Upload image from sender + operationId: uploadSenderImage + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '201': + description: Image uploaded + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/sender/note: + post: + tags: [External] + summary: Save note from sender + operationId: saveSenderNote + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + responses: + '201': + description: Note saved + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + # LLM endpoints + /api/llm/chat: + post: + tags: [LLM] + summary: Create new chat session + operationId: createChatSession + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + systemPrompt: + type: string + temperature: + type: number + minimum: 0 + maximum: 1 + maxTokens: + type: integer + model: + type: string + provider: + type: string + enum: [openai, anthropic, ollama] + contextNoteId: + type: string + responses: + '201': + description: Chat session created + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + get: + tags: [LLM] + summary: List all chat sessions + operationId: listChatSessions + responses: + '200': + description: Chat sessions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ChatSession' + + /api/llm/chat/{chatNoteId}: + get: + tags: [LLM] + summary: Get specific chat session + operationId: getChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Chat session details + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + patch: + tags: [LLM] + summary: Update chat session + operationId: updateChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + systemPrompt: + type: string + temperature: + type: number + maxTokens: + type: integer + model: + type: string + provider: + type: string + contextNoteId: + type: string + responses: + '200': + description: Session updated + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + delete: + tags: [LLM] + summary: Delete chat session + operationId: deleteChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Session deleted + + /api/llm/chat/{chatNoteId}/messages: + post: + tags: [LLM] + summary: Send message to LLM + operationId: sendChatMessage + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [message] + properties: + message: + type: string + options: + type: object + properties: + temperature: + type: number + maxTokens: + type: integer + model: + type: string + provider: + type: string + includeContext: + type: boolean + useNoteContext: + type: boolean + responses: + '200': + description: LLM response + content: + application/json: + schema: + type: object + properties: + response: + type: string + sources: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + similarity: + type: number + + /api/llm/chat/{chatNoteId}/messages/stream: + post: + tags: [LLM] + summary: Stream message to LLM + operationId: streamChatMessage + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [content] + properties: + content: + type: string + useAdvancedContext: + type: boolean + showThinking: + type: boolean + mentions: + type: array + items: + type: string + responses: + '200': + description: Streaming started + + /api/llm/providers/ollama/models: + get: + tags: [LLM] + summary: List Ollama models + operationId: listOllamaModels + parameters: + - name: baseUrl + in: query + schema: + type: string + responses: + '200': + description: Ollama models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + models: + type: array + items: + type: object + + /api/llm/providers/openai/models: + get: + tags: [LLM] + summary: List OpenAI models + operationId: listOpenAIModels + responses: + '200': + description: OpenAI models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + chatModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + embeddingModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + + /api/llm/providers/anthropic/models: + get: + tags: [LLM] + summary: List Anthropic models + operationId: listAnthropicModels + responses: + '200': + description: Anthropic models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + chatModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + + # TOTP/2FA + /api/totp/generate: + get: + tags: [Security] + summary: Generate TOTP secret + operationId: generateTotpSecret + responses: + '200': + description: TOTP secret generated + content: + application/json: + schema: + type: object + properties: + secret: + type: string + qrCode: + type: string + + /api/totp/status: + get: + tags: [Security] + summary: Get TOTP status + operationId: getTotpStatus + responses: + '200': + description: TOTP status + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + + # ETAPI tokens + /api/etapi-tokens: + get: + tags: [Security] + summary: List ETAPI tokens + operationId: listEtapiTokens + responses: + '200': + description: ETAPI tokens + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EtapiToken' + + post: + tags: [Security] + summary: Create ETAPI token + operationId: createEtapiToken + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [name] + properties: + name: + type: string + responses: + '201': + description: Token created + content: + application/json: + schema: + $ref: '#/components/schemas/EtapiToken' + + /api/etapi-tokens/{etapiTokenId}: + patch: + tags: [Security] + summary: Update ETAPI token + operationId: updateEtapiToken + parameters: + - name: etapiTokenId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + responses: + '200': + description: Token updated + content: + application/json: + schema: + $ref: '#/components/schemas/EtapiToken' + + delete: + tags: [Security] + summary: Delete ETAPI token + operationId: deleteEtapiToken + parameters: + - name: etapiTokenId + in: path + required: true + schema: + type: string + responses: + '204': + description: Token deleted + + # Other utilities + /api/stats/note-size/{noteId}: + get: + tags: [Utilities] + summary: Get note size + operationId: getNoteSize + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note size + content: + application/json: + schema: + type: object + properties: + size: + type: integer + + /api/stats/subtree-size/{noteId}: + get: + tags: [Utilities] + summary: Get subtree size + operationId: getSubtreeSize + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Subtree size + content: + application/json: + schema: + type: object + properties: + size: + type: integer + + /api/keyboard-actions: + get: + tags: [Utilities] + summary: Get keyboard actions + operationId: getKeyboardActions + responses: + '200': + description: Keyboard actions + content: + application/json: + schema: + type: array + items: + type: object + properties: + actionName: + type: string + shortcut: + type: string + description: + type: string + + /api/fonts: + get: + tags: [Utilities] + summary: Get font CSS + operationId: getFonts + responses: + '200': + description: Font CSS + content: + text/css: + schema: + type: string + + /api/recent-notes: + post: + tags: [Utilities] + summary: Add recent note + operationId: addRecentNote + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [noteId] + properties: + noteId: + type: string + responses: + '204': + description: Note added to recent + + /api/recent-changes/{ancestorNoteId}: + get: + tags: [Utilities] + summary: Get recent changes + operationId: getRecentChanges + parameters: + - name: ancestorNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Recent changes + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + dateModified: + type: string + format: date-time + + /api/other/icon-usage: + get: + tags: [Utilities] + summary: Get icon usage statistics + operationId: getIconUsage + responses: + '200': + description: Icon usage stats + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + + /api/other/render-markdown: + post: + tags: [Utilities] + summary: Render markdown to HTML + operationId: renderMarkdown + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [markdownContent] + properties: + markdownContent: + type: string + responses: + '200': + description: Rendered HTML + content: + text/html: + schema: + type: string + +components: + securitySchemes: + sessionAuth: + type: apiKey + in: cookie + name: trilium.sid + description: Session cookie obtained from login + + tokenAuth: + type: apiKey + in: header + name: Authorization + description: API token in format "Bearer {token}" + + parameters: + noteId: + name: noteId + in: path + required: true + schema: + type: string + description: 12-character note ID + + schemas: + Note: + type: object + required: + - noteId + - title + - type + - mime + - isProtected + properties: + noteId: + type: string + description: 12-character note ID + example: ur11rSfHkzeV + title: + type: string + description: Note title + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + description: MIME type + example: text/html + isProtected: + type: boolean + description: Whether note is protected + blobId: + type: string + description: ID of content blob + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + NoteType: + type: string + enum: + - text + - code + - render + - file + - image + - search + - relationMap + - book + - noteMap + - mermaid + - canvas + - webView + - launcher + - doc + - contentWidget + - mindMap + - geoMap + + Branch: + type: object + required: + - branchId + - noteId + - parentNoteId + - notePosition + properties: + branchId: + type: string + description: Branch ID (parentNoteId_noteId) + noteId: + type: string + parentNoteId: + type: string + notePosition: + type: integer + prefix: + type: string + nullable: true + isExpanded: + type: boolean + + Attribute: + type: object + required: + - attributeId + - noteId + - type + - name + - value + properties: + attributeId: + type: string + noteId: + type: string + type: + type: string + enum: [label, relation] + name: + type: string + value: + type: string + position: + type: integer + isInheritable: + type: boolean + + Attachment: + type: object + required: + - attachmentId + - ownerId + - role + - mime + - title + properties: + attachmentId: + type: string + ownerId: + type: string + role: + type: string + enum: [image, file] + mime: + type: string + title: + type: string + blobId: + type: string + dateModified: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + Revision: + type: object + properties: + revisionId: + type: string + noteId: + type: string + title: + type: string + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + dateCreated: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + + SearchResult: + type: object + properties: + noteId: + type: string + title: + type: string + path: + type: string + score: + type: number + highlights: + type: array + items: + type: string + + EntityChange: + type: object + properties: + entityChange: + type: object + properties: + entityName: + type: string + changeId: + type: string + entity: + type: object + + Timestamps: + type: object + properties: + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + CreateNoteRequest: + type: object + required: + - title + - type + properties: + title: + type: string + content: + type: string + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + isProtected: + type: boolean + isExpanded: + type: boolean + notePosition: + type: integer + prefix: + type: string + parentNoteId: + type: string + templateNoteId: + type: string + + ScriptBundle: + type: object + properties: + noteId: + type: string + script: + type: string + html: + type: string + css: + type: string + + AppInfo: + type: object + properties: + appVersion: + type: string + example: 0.91.6 + dbVersion: + type: integer + example: 228 + nodeVersion: + type: string + syncVersion: + type: integer + example: 34 + buildDate: + type: string + format: date-time + buildRevision: + type: string + dataDirectory: + type: string + clipperProtocolVersion: + type: string + utcDateTime: + type: string + format: date-time + + ChatSession: + type: object + properties: + sessionId: + type: string + title: + type: string + messages: + type: array + items: + type: object + properties: + role: + type: string + enum: [user, assistant, system] + content: + type: string + timestamp: + type: string + format: date-time + createdAt: + type: string + format: date-time + lastActive: + type: string + format: date-time + messageCount: + type: integer + + EtapiToken: + type: object + properties: + etapiTokenId: + type: string + name: + type: string + token: + type: string + dateCreated: + type: string + format: date-time + isDeleted: + type: boolean \ No newline at end of file diff --git a/apps/server/src/routes/api_docs.ts b/apps/server/src/routes/api_docs.ts index 122ae44b0..4b0b9f0ca 100644 --- a/apps/server/src/routes/api_docs.ts +++ b/apps/server/src/routes/api_docs.ts @@ -3,12 +3,22 @@ import swaggerUi from "swagger-ui-express"; import { join } from "path"; import yaml from "js-yaml"; import type { JsonObject } from "swagger-ui-express"; -import { readFileSync } from "fs"; +import { readFileSync, existsSync } from "fs"; import { RESOURCE_DIR } from "../services/resource_dir"; export default function register(app: Application) { const etapiDocument = yaml.load(readFileSync(join(RESOURCE_DIR, "etapi.openapi.yaml"), "utf8")) as JsonObject; - const apiDocument = JSON.parse(readFileSync(join(RESOURCE_DIR, "openapi.json"), "utf-8")); + + // Load the comprehensive API documentation (YAML) if available, otherwise fall back to JSON + const apiYamlPath = join(RESOURCE_DIR, "api-openapi.yaml"); + const apiJsonPath = join(RESOURCE_DIR, "openapi.json"); + + let apiDocument: JsonObject; + if (existsSync(apiYamlPath)) { + apiDocument = yaml.load(readFileSync(apiYamlPath, "utf8")) as JsonObject; + } else { + apiDocument = JSON.parse(readFileSync(apiJsonPath, "utf-8")); + } app.use( "/etapi/docs/", @@ -24,7 +34,8 @@ export default function register(app: Application) { swaggerUi.serveFiles(apiDocument), swaggerUi.setup(apiDocument, { explorer: true, - customSiteTitle: "TriliumNext Internal API Documentation" + customSiteTitle: "TriliumNext Internal API Documentation", + customCss: '.swagger-ui .topbar { display: none }' }) ); } From d3589243244de162b10dce997eec971a62592ad4 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 17:14:44 +0000 Subject: [PATCH 2/4] feat(docs): implement swagger ui endpoint for internal api --- apps/server/src/assets/api-openapi.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/server/src/assets/api-openapi.yaml b/apps/server/src/assets/api-openapi.yaml index f8b5ebf81..6d3bf51cb 100644 --- a/apps/server/src/assets/api-openapi.yaml +++ b/apps/server/src/assets/api-openapi.yaml @@ -1,12 +1,12 @@ openapi: 3.1.0 info: title: Trilium Notes Internal API - version: 0.94.0 + version: 0.98.0 description: | This is the internal API used by the Trilium Notes client application. **Important:** This API is primarily intended for internal use by the Trilium client. - For external integrations, please use the [ETAPI (External Trilium API)](https://triliumnext.github.io/Docs/Wiki/etapi.html) instead. + For external integrations, please use the [ETAPI (External Trilium API)](https://github.com/TriliumNext/Trilium/blob/main/docs/User%20Guide/User%20Guide/Advanced%20Usage/ETAPI%20(REST%20API).md#etapi-rest-api) instead. ## Authentication @@ -25,7 +25,7 @@ info: contact: name: TriliumNext Issue Tracker - url: https://github.com/TriliumNext/Notes/issues + url: https://github.com/TriliumNext/Trilium/issues license: name: GNU Affero General Public License v3.0 url: https://www.gnu.org/licenses/agpl-3.0.html @@ -4109,4 +4109,4 @@ components: type: string format: date-time isDeleted: - type: boolean \ No newline at end of file + type: boolean From 05c73011f5a7ad567795e350291cb7e398a8fceb Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 17:30:26 +0000 Subject: [PATCH 3/4] feat(docs): add additional api routes --- apps/server/src/assets/api-openapi.yaml | 575 +++++++++++++++++++++++- 1 file changed, 565 insertions(+), 10 deletions(-) diff --git a/apps/server/src/assets/api-openapi.yaml b/apps/server/src/assets/api-openapi.yaml index 6d3bf51cb..8ca257b39 100644 --- a/apps/server/src/assets/api-openapi.yaml +++ b/apps/server/src/assets/api-openapi.yaml @@ -218,6 +218,49 @@ paths: '204': description: Session refreshed + # OAuth endpoints + /api/oauth/status: + get: + tags: [Authentication] + summary: Get OAuth status + operationId: getOAuthStatus + responses: + '200': + description: OAuth status + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + configured: + type: boolean + providers: + type: array + items: + type: string + + /api/oauth/validate: + get: + tags: [Authentication] + summary: Validate OAuth configuration + operationId: validateOAuth + responses: + '200': + description: OAuth validation result + content: + application/json: + schema: + type: object + properties: + valid: + type: boolean + errors: + type: array + items: + type: string + # App Info /api/app-info: get: @@ -302,6 +345,29 @@ paths: responses: '200': description: Sync setup successful + + /api/setup/sync-seed: + get: + tags: [Configuration, Sync] + summary: Get sync seed for setup + operationId: getSyncSeed + security: [] + responses: + '200': + description: Sync seed information + content: + application/json: + schema: + type: object + properties: + syncVersion: + type: integer + schemaVersion: + type: integer + documentSecret: + type: string + maxSyncId: + type: integer # Note operations /api/notes/{noteId}: @@ -660,7 +726,7 @@ paths: type: string format: binary - /api/notes/{noteId}/download: + /api/notes/download/{noteId}: get: tags: [Notes] summary: Download file note @@ -681,13 +747,38 @@ paths: type: string format: binary - /api/notes/{noteId}/open-partial: + /api/notes/{noteId}/download: get: tags: [Notes] - summary: Stream file with partial content support - operationId: openPartialFileNote + summary: Download file note (alternative path) + operationId: downloadFileNoteAlt parameters: - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/open-partial: + get: + tags: [Attachments] + summary: Stream file with partial content support + operationId: openPartialFileAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string - name: Range in: header schema: @@ -1477,7 +1568,7 @@ paths: type: string format: binary - /api/attachments/{attachmentId}/download: + /api/attachments/download/{attachmentId}: get: tags: [Attachments] summary: Download attachment @@ -1501,6 +1592,128 @@ paths: schema: type: string format: binary + + /api/attachments/{attachmentId}/download: + get: + tags: [Attachments] + summary: Download attachment (alternative path) + operationId: downloadAttachmentAlt + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/all: + get: + tags: [Attachments] + summary: Get all attachment information + operationId: getAllAttachmentInfo + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Complete attachment information + content: + application/json: + schema: + type: object + properties: + attachmentId: + type: string + title: + type: string + mime: + type: string + isProtected: + type: boolean + position: + type: integer + contentLength: + type: integer + ownerId: + type: string + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + + /api/attachments/{attachmentId}/save-to-tmp-dir: + post: + tags: [Attachments] + summary: Save attachment to temporary directory + operationId: saveAttachmentToTmpDir + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment saved to temporary directory + content: + application/json: + schema: + type: object + properties: + tmpPath: + type: string + description: Path to temporary file + success: + type: boolean + + /api/attachments/{attachmentId}/upload-modified-file: + post: + tags: [Attachments] + summary: Upload modified attachment file + operationId: uploadModifiedAttachmentFile + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '200': + description: Modified file uploaded + content: + application/json: + schema: + type: object + properties: + success: + type: boolean # Revisions /api/notes/{noteId}/revisions: @@ -2970,6 +3183,159 @@ paths: application/json: schema: $ref: '#/components/schemas/Note' + + /api/special-notes/notes-for-month/{month}: + get: + tags: [Special Notes] + summary: Get notes for specific month + operationId: getNotesForMonth + parameters: + - name: month + in: path + required: true + schema: + type: string + example: "2024-03" + responses: + '200': + description: Notes for the month + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + /api/special-notes/quarters/{quarter}: + get: + tags: [Special Notes] + summary: Get quarter note + operationId: getQuarter + parameters: + - name: quarter + in: path + required: true + schema: + type: string + example: "2024-Q1" + responses: + '200': + description: Quarter note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/week-first-day/{date}: + get: + tags: [Special Notes] + summary: Get first day of week for date + operationId: getWeekFirstDay + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + example: "2024-03-15" + responses: + '200': + description: First day of week + content: + application/json: + schema: + type: object + properties: + date: + type: string + format: date + + /api/special-notes/launchers/{noteId}/reset: + post: + tags: [Special Notes] + summary: Reset launcher note + operationId: resetLauncher + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Launcher reset + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/save-search-note: + post: + tags: [Special Notes] + summary: Save search note + operationId: saveSearchNote + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + query: + type: string + title: + type: string + responses: + '201': + description: Search note saved + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/save-sql-console: + post: + tags: [Special Notes] + summary: Save SQL console note + operationId: saveSqlConsole + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + sql: + type: string + title: + type: string + responses: + '201': + description: SQL console saved + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/api-script-launcher: + put: + tags: [Special Notes] + summary: Update API script launcher + operationId: updateApiScriptLauncher + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + description: Script code + responses: + '200': + description: API script launcher updated + content: + application/json: + schema: + $ref: '#/components/schemas/Note' # Maps /api/note-map/{noteId}/tree: @@ -3024,6 +3390,25 @@ paths: title: type: string + /api/note-map/{noteId}/backlink-count: + get: + tags: [Visualization] + summary: Get backlink count for note + operationId: getBacklinkCount + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Backlink count + content: + application/json: + schema: + type: object + properties: + count: + type: integer + description: Number of backlinks to this note + /api/relation-map: post: tags: [Visualization] @@ -3119,6 +3504,27 @@ paths: schema: $ref: '#/components/schemas/Note' + /api/clipper/open/{noteId}: + post: + tags: [External] + summary: Open note in clipper + operationId: openNoteInClipper + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note opened in clipper + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + url: + type: string + description: URL to open in clipper + /api/sender/login: post: tags: [External] @@ -3247,13 +3653,13 @@ paths: items: $ref: '#/components/schemas/ChatSession' - /api/llm/chat/{chatNoteId}: + /api/llm/chat/{sessionId}: get: tags: [LLM] summary: Get specific chat session operationId: getChatSession parameters: - - name: chatNoteId + - name: sessionId in: path required: true schema: @@ -3271,7 +3677,7 @@ paths: summary: Update chat session operationId: updateChatSession parameters: - - name: chatNoteId + - name: sessionId in: path required: true schema: @@ -3305,6 +3711,7 @@ paths: schema: $ref: '#/components/schemas/ChatSession' + /api/llm/chat/{chatNoteId}: delete: tags: [LLM] summary: Delete chat session @@ -3325,7 +3732,7 @@ paths: summary: Send message to LLM operationId: sendChatMessage parameters: - - name: chatNoteId + - name: sessionId in: path required: true schema: @@ -3383,7 +3790,7 @@ paths: summary: Stream message to LLM operationId: streamChatMessage parameters: - - name: chatNoteId + - name: sessionId in: path required: true schema: @@ -3535,6 +3942,132 @@ paths: enabled: type: boolean + /api/totp/get: + get: + tags: [Security] + summary: Get TOTP configuration + operationId: getTotpConfig + responses: + '200': + description: TOTP configuration + content: + application/json: + schema: + type: object + properties: + secret: + type: string + qrCode: + type: string + backupCodes: + type: array + items: + type: string + + /api/totp_recovery/enabled: + get: + tags: [Security] + summary: Check if TOTP recovery is enabled + operationId: isTotpRecoveryEnabled + responses: + '200': + description: TOTP recovery status + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + + /api/totp_recovery/generate: + get: + tags: [Security] + summary: Generate TOTP recovery codes + operationId: generateTotpRecoveryCodes + responses: + '200': + description: Generated recovery codes + content: + application/json: + schema: + type: object + properties: + codes: + type: array + items: + type: string + + /api/totp_recovery/used: + get: + tags: [Security] + summary: Get used TOTP recovery codes + operationId: getUsedTotpRecoveryCodes + responses: + '200': + description: Used recovery codes + content: + application/json: + schema: + type: object + properties: + usedCodes: + type: array + items: + type: string + + /api/totp_recovery/set: + post: + tags: [Security] + summary: Set TOTP recovery codes + operationId: setTotpRecoveryCodes + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + codes: + type: array + items: + type: string + responses: + '200': + description: Recovery codes set + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + + /api/totp_recovery/verify: + post: + tags: [Security] + summary: Verify TOTP recovery code + operationId: verifyTotpRecoveryCode + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + code: + type: string + responses: + '200': + description: Verification result + content: + application/json: + schema: + type: object + properties: + valid: + type: boolean + # ETAPI tokens /api/etapi-tokens: get: @@ -3674,6 +4207,28 @@ paths: description: type: string + /api/keyboard-shortcuts-for-notes: + get: + tags: [Utilities] + summary: Get keyboard shortcuts for notes + operationId: getKeyboardShortcutsForNotes + responses: + '200': + description: Keyboard shortcuts for notes + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + shortcut: + type: string + title: + type: string + /api/fonts: get: tags: [Utilities] From 53ed510c92c9d86b68b4a28b451757d80545d5af Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 17:36:22 +0000 Subject: [PATCH 4/4] feat(docs): remove old json api docs --- apps/server/src/assets/openapi.json | 1 - apps/server/src/routes/api_docs.ts | 14 +++----------- 2 files changed, 3 insertions(+), 12 deletions(-) delete mode 100644 apps/server/src/assets/openapi.json diff --git a/apps/server/src/assets/openapi.json b/apps/server/src/assets/openapi.json deleted file mode 100644 index b019c4a65..000000000 --- a/apps/server/src/assets/openapi.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.1.1","info":{"title":"Trilium Notes - Sync server API","version":"0.94.0","description":"This is the internal sync server API used by Trilium Notes / Trilium Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).","contact":{"name":"TriliumNext issue tracker","url":"https://github.com/TriliumNext/Notes/issues"},"license":{"name":"GNU Free Documentation License 1.3 (or later)","url":"https://www.gnu.org/licenses/fdl-1.3"}},"paths":{"/api/setup/sync-seed":{"get":{"tags":["auth"],"summary":"Sync documentSecret value","description":"First step to logging in.","operationId":"setup-sync-seed","responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"syncVersion":{"type":"integer","example":34},"options":{"type":"object","properties":{"documentSecret":{"type":"string"}}}}}}}}},"security":[{"user-password":[]}]}},"/api/anthropic/models":{"post":{"summary":"List available models from Anthropic","operationId":"anthropic-list-models","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"baseUrl":{"type":"string","description":"Optional custom Anthropic API base URL"}}}}}},"responses":{"200":{"description":"List of available Anthropic models","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"chatModels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}}},"embeddingModels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}}}}}}}},"500":{"description":"Error listing models"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/app-info":{"get":{"summary":"Get installation info","operationId":"app-info","externalDocs":{"description":"Server implementation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/app_info.ts"},"responses":{"200":{"description":"Installation info","content":{"application/json":{"schema":{"type":"object","properties":{"appVersion":{"type":"string","example":"0.91.6"},"dbVersion":{"type":"integer","example":228},"nodeVersion":{"type":"string","description":"value of process.version"},"syncVersion":{"type":"integer","example":34},"buildDate":{"type":"string","example":"2024-09-07T18:36:34Z"},"buildRevision":{"type":"string","example":"7c0d6930fa8f20d269dcfbcbc8f636a25f6bb9a7"},"dataDirectory":{"type":"string","example":"/var/lib/trilium"},"clipperProtocolVersion":{"type":"string","example":"1.0"},"utcDateTime":{"$ref":"#/components/schemas/UtcDateTime"}}}}}}},"security":[{"session":[]}]}},"/api/branches/{branchId}":{"delete":{"summary":"Delete branch (note clone)","operationId":"branches-delete","parameters":[{"name":"branchId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/BranchId"}},{"name":"taskId","in":"query","required":true,"schema":{"type":"string"},"description":"Task group identifier"},{"name":"eraseNotes","in":"query","schema":{"type":"boolean"},"required":false,"description":"Whether to erase the note immediately"},{"name":"last","in":"query","schema":{"type":"boolean"},"required":true,"description":"Whether this is the last request of this task group"}],"responses":{"200":{"description":"Branch successfully deleted","content":{"application/json":{"schema":{"type":"object","properties":{"noteDeleted":{"type":"boolean","description":"Whether the last note clone was deleted"}}}}}}},"security":[{"session":[]}],"tags":["data"]}},"/api/llm/embeddings/similar/{noteId}":{"get":{"summary":"Find similar notes based on a given note ID","operationId":"embeddings-similar-by-note","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"type":"string"}},{"name":"providerId","in":"query","required":false,"schema":{"type":"string"},"default":"openai","description":"Embedding provider ID"},{"name":"modelId","in":"query","required":false,"schema":{"type":"string"},"default":"text-embedding-3-small","description":"Embedding model ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"default":10,"description":"Maximum number of similar notes to return"},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","format":"float"},"default":0.7,"description":"Similarity threshold (0.0-1.0)"}],"responses":{"200":{"description":"List of similar notes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"similarNotes":{"type":"array","items":{"type":"object","properties":{"noteId":{"type":"string"},"title":{"type":"string"},"similarity":{"type":"number","format":"float"}}}}}}}}},"400":{"description":"Invalid request parameters"},"404":{"description":"Note not found"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/search":{"post":{"summary":"Search for notes similar to provided text","operationId":"embeddings-search-by-text","parameters":[{"name":"providerId","in":"query","required":false,"schema":{"type":"string"},"default":"openai","description":"Embedding provider ID"},{"name":"modelId","in":"query","required":false,"schema":{"type":"string"},"default":"text-embedding-3-small","description":"Embedding model ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"default":10,"description":"Maximum number of similar notes to return"},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","format":"float"},"default":0.7,"description":"Similarity threshold (0.0-1.0)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","description":"Text to search with"}}}}}},"responses":{"200":{"description":"List of similar notes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"similarNotes":{"type":"array","items":{"type":"object","properties":{"noteId":{"type":"string"},"title":{"type":"string"},"similarity":{"type":"number","format":"float"}}}}}}}}},"400":{"description":"Invalid request parameters"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/providers":{"get":{"summary":"Get available embedding providers","operationId":"embeddings-get-providers","responses":{"200":{"description":"List of available embedding providers","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"providers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"isEnabled":{"type":"boolean"},"priority":{"type":"integer"},"config":{"type":"object"}}}}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/providers/{providerId}":{"patch":{"summary":"Update embedding provider configuration","operationId":"embeddings-update-provider","parameters":[{"name":"providerId","in":"path","required":true,"schema":{"type":"string"},"description":"Provider ID to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether provider is enabled"},"priority":{"type":"integer","description":"Priority order (lower is higher priority)"},"config":{"type":"object","description":"Provider-specific configuration"}}}}}},"responses":{"200":{"description":"Provider updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"Invalid provider ID or configuration"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/reprocess":{"post":{"summary":"Reprocess embeddings for all notes","operationId":"embeddings-reprocess-all","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"providerId":{"type":"string","description":"Provider ID to use for reprocessing"},"modelId":{"type":"string","description":"Model ID to use for reprocessing"},"forceReprocess":{"type":"boolean","description":"Whether to reprocess notes that already have embeddings"}}}}}},"responses":{"200":{"description":"Reprocessing started","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"jobId":{"type":"string"},"message":{"type":"string"}}}}}},"400":{"description":"Invalid provider ID or configuration"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/queue-status":{"get":{"summary":"Get status of the embedding processing queue","operationId":"embeddings-queue-status","parameters":[{"name":"jobId","in":"query","required":false,"schema":{"type":"string"},"description":"Optional job ID to get status for a specific processing job"}],"responses":{"200":{"description":"Queue status information","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"string","enum":["idle","processing","paused"]},"progress":{"type":"number","format":"float","description":"Progress percentage (0-100)"},"details":{"type":"object"}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/stats":{"get":{"summary":"Get embedding statistics","operationId":"embeddings-stats","responses":{"200":{"description":"Embedding statistics","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"stats":{"type":"object","properties":{"totalEmbeddings":{"type":"integer"},"providers":{"type":"object"},"modelCounts":{"type":"object"},"lastUpdated":{"type":"string","format":"date-time"}}}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/failed":{"get":{"summary":"Get list of notes that failed embedding generation","operationId":"embeddings-failed-notes","responses":{"200":{"description":"List of failed notes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"failedNotes":{"type":"array","items":{"type":"object","properties":{"noteId":{"type":"string"},"title":{"type":"string"},"error":{"type":"string"},"failedAt":{"type":"string","format":"date-time"}}}}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/retry/{noteId}":{"post":{"summary":"Retry generating embeddings for a failed note","operationId":"embeddings-retry-note","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"type":"string"},"description":"Note ID to retry"},{"name":"providerId","in":"query","required":false,"schema":{"type":"string"},"description":"Provider ID to use (defaults to configured default)"},{"name":"modelId","in":"query","required":false,"schema":{"type":"string"},"description":"Model ID to use (defaults to provider default)"}],"responses":{"200":{"description":"Retry result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Invalid request"},"404":{"description":"Note not found"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/retry-all-failed":{"post":{"summary":"Retry generating embeddings for all failed notes","operationId":"embeddings-retry-all-failed","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"providerId":{"type":"string","description":"Provider ID to use (defaults to configured default)"},"modelId":{"type":"string","description":"Model ID to use (defaults to provider default)"}}}}}},"responses":{"200":{"description":"Retry started","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"jobId":{"type":"string"}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/rebuild-index":{"post":{"summary":"Rebuild the vector store index","operationId":"embeddings-rebuild-index","responses":{"200":{"description":"Rebuild started","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"jobId":{"type":"string"}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/embeddings/index-rebuild-status":{"get":{"summary":"Get status of the vector index rebuild operation","operationId":"embeddings-rebuild-status","parameters":[{"name":"jobId","in":"query","required":false,"schema":{"type":"string"},"description":"Optional job ID to get status for a specific rebuild job"}],"responses":{"200":{"description":"Rebuild status information","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"string","enum":["idle","in_progress","completed","failed"]},"progress":{"type":"number","format":"float","description":"Progress percentage (0-100)"},"message":{"type":"string"},"details":{"type":"object","properties":{"startTime":{"type":"string","format":"date-time"},"processed":{"type":"integer"},"total":{"type":"integer"}}}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/sessions":{"post":{"summary":"Create a new LLM chat session","operationId":"llm-create-session","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Title for the chat session"},"systemPrompt":{"type":"string","description":"System message to set the behavior of the assistant"},"temperature":{"type":"number","description":"Temperature parameter for the LLM (0.0-1.0)"},"maxTokens":{"type":"integer","description":"Maximum tokens to generate in responses"},"model":{"type":"string","description":"Specific model to use (depends on provider)"},"provider":{"type":"string","description":"LLM provider to use (e.g., 'openai', 'anthropic', 'ollama')"},"contextNoteId":{"type":"string","description":"Note ID to use as context for the session"}}}}}},"responses":{"200":{"description":"Successfully created session","content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string"},"title":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}},"security":[{"session":[]}],"tags":["llm"]},"get":{"summary":"List all chat sessions","operationId":"llm-list-sessions","responses":{"200":{"description":"List of chat sessions","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"lastActive":{"type":"string","format":"date-time"},"messageCount":{"type":"integer"}}}}}}}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/sessions/{sessionId}":{"get":{"summary":"Retrieve a specific chat session","operationId":"llm-get-session","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chat session details","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant","system"]},"content":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}},"createdAt":{"type":"string","format":"date-time"},"lastActive":{"type":"string","format":"date-time"}}}}}},"404":{"description":"Session not found"}},"security":[{"session":[]}],"tags":["llm"]},"delete":{"summary":"Delete a chat session","operationId":"llm-delete-session","parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session successfully deleted"},"404":{"description":"Session not found"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/chat/{chatNoteId}":{"patch":{"summary":"Update a chat's settings","operationId":"llm-update-chat","parameters":[{"name":"chatNoteId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the chat note (formerly sessionId)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Updated title for the session"},"systemPrompt":{"type":"string","description":"Updated system prompt"},"temperature":{"type":"number","description":"Updated temperature setting"},"maxTokens":{"type":"integer","description":"Updated maximum tokens setting"},"model":{"type":"string","description":"Updated model selection"},"provider":{"type":"string","description":"Updated provider selection"},"contextNoteId":{"type":"string","description":"Updated note ID for context"}}}}}},"responses":{"200":{"description":"Session successfully updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"404":{"description":"Session not found"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/chat/{chatNoteId}/messages":{"post":{"summary":"Send a message to an LLM and get a response","operationId":"llm-send-message","parameters":[{"name":"chatNoteId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the chat note (formerly sessionId)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"The user message to send to the LLM"},"options":{"type":"object","description":"Optional parameters for this specific message","properties":{"temperature":{"type":"number"},"maxTokens":{"type":"integer"},"model":{"type":"string"},"provider":{"type":"string"}}},"includeContext":{"type":"boolean","description":"Whether to include relevant notes as context"},"useNoteContext":{"type":"boolean","description":"Whether to use the session's context note"}}}}}},"responses":{"200":{"description":"LLM response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"},"sources":{"type":"array","items":{"type":"object","properties":{"noteId":{"type":"string"},"title":{"type":"string"},"similarity":{"type":"number"}}}},"sessionId":{"type":"string"}}}}}},"404":{"description":"Session not found"},"500":{"description":"Error processing request"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes/stats":{"get":{"summary":"Get stats about the LLM knowledge base indexing status","operationId":"llm-index-stats","responses":{"200":{"description":"Index stats successfully retrieved"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes":{"post":{"summary":"Start or continue indexing the knowledge base","operationId":"llm-start-indexing","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Whether to force reindexing of all notes"}}}}}},"responses":{"200":{"description":"Indexing started successfully"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes/failed":{"get":{"summary":"Get list of notes that failed to index","operationId":"llm-failed-indexes","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100}}],"responses":{"200":{"description":"Failed indexes successfully retrieved"}},"security":[{"session":[]}],"tags":["llm"]},"put":{"summary":"Retry indexing all failed notes","operationId":"llm-retry-all-indexes","responses":{"200":{"description":"Retry of all failed indexes successfully initiated"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes/notes/{noteId}":{"put":{"summary":"Retry indexing a specific note that previously failed","operationId":"llm-retry-index","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Index retry successfully initiated"}},"security":[{"session":[]}],"tags":["llm"]},"post":{"summary":"Index a specific note for LLM knowledge base","operationId":"llm-index-note","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Note indexed successfully"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes/notes/similar":{"get":{"summary":"Find notes similar to a query string","operationId":"llm-find-similar-notes","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"}},{"name":"contextNoteId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":5}}],"responses":{"200":{"description":"Similar notes found successfully"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/indexes/context":{"get":{"summary":"Generate context for an LLM query based on the knowledge base","operationId":"llm-generate-context","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"}},{"name":"contextNoteId","in":"query","required":false,"schema":{"type":"string"}},{"name":"depth","in":"query","required":false,"schema":{"type":"integer","default":2}}],"responses":{"200":{"description":"Context generated successfully"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/llm/chat/{chatNoteId}/messages/stream":{"post":{"summary":"Stream a message to an LLM via WebSocket","operationId":"llm-stream-message","parameters":[{"name":"chatNoteId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the chat note to stream messages to (formerly sessionId)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","description":"The user message to send to the LLM"},"useAdvancedContext":{"type":"boolean","description":"Whether to use advanced context extraction"},"showThinking":{"type":"boolean","description":"Whether to show thinking process in the response"}}}}}},"responses":{"200":{"description":"Streaming started successfully"},"404":{"description":"Session not found"},"500":{"description":"Error processing request"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/login/sync":{"post":{"tags":["auth"],"summary":"Log in using documentSecret","description":"The `hash` parameter is computed using a HMAC of the `documentSecret` and `timestamp`.","operationId":"login-sync","externalDocs":{"description":"HMAC calculation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/utils.ts#L62-L66"},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"timestamp":{"$ref":"#/components/schemas/UtcDateTime"},"hash":{"type":"string"},"syncVersion":{"type":"integer","example":34}}}}}},"responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"type":"object","properties":{"syncVersion":{"type":"integer","example":34},"options":{"type":"object","properties":{"documentSecret":{"type":"string"}}}}}}}},"400":{"description":"Sync version / document secret mismatch","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Non-matching sync versions, local is version ${server syncVersion}, remote is ${requested syncVersion}. It is recommended to run same version of Trilium on both sides of sync"}}}}}},"401":{"description":"Timestamp mismatch","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auth request time is out of sync, please check that both client and server have correct time. The difference between clocks has to be smaller than 5 minutes"}}}}}}}}},"/api/notes/{noteId}":{"get":{"summary":"Retrieve note metadata","operationId":"notes-get","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/NoteId"}}],"responses":{"200":{"description":"Note metadata","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Note"},{"$ref":"#/components/schemas/Timestamps"}]}}}}},"security":[{"session":[]}],"tags":["data"]},"delete":{"summary":"Delete note","operationId":"notes-delete","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/NoteId"}},{"name":"taskId","in":"query","required":true,"schema":{"type":"string"},"description":"Task group identifier"},{"name":"eraseNotes","in":"query","schema":{"type":"boolean"},"required":false,"description":"Whether to erase the note immediately"},{"name":"last","in":"query","schema":{"type":"boolean"},"required":true,"description":"Whether this is the last request of this task group"}],"responses":{"200":{"description":"Note successfully deleted"}},"security":[{"session":[]}],"tags":["data"]}},"/api/notes/{noteId}/blob":{"get":{"summary":"Retrieve note content","operationId":"notes-blob","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/NoteId"}}],"responses":{"304":{"description":"Note content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blob"}}}}},"security":[{"session":[]}],"tags":["data"]}},"/api/notes/{noteId}/metadata":{"get":{"summary":"Retrieve note metadata (limited to timestamps)","operationId":"notes-metadata","parameters":[{"name":"noteId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/NoteId"}}],"responses":{"200":{"description":"Note metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Timestamps"}}}}},"security":[{"session":[]}],"tags":["data"]}},"/api/llm/providers/ollama/models":{"get":{"summary":"List available models from Ollama","operationId":"ollama-list-models","parameters":[{"name":"baseUrl","in":"query","required":false,"schema":{"type":"string"},"description":"Optional custom Ollama API base URL"}],"responses":{"200":{"description":"List of available Ollama models","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"models":{"type":"array","items":{"type":"object"}}}}}}},"500":{"description":"Error listing models"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/openai/models":{"post":{"summary":"List available models from OpenAI","operationId":"openai-list-models","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"baseUrl":{"type":"string","description":"Optional custom OpenAI API base URL"}}}}}},"responses":{"200":{"description":"List of available OpenAI models","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"chatModels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}}},"embeddingModels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}}}}}}}},"500":{"description":"Error listing models"}},"security":[{"session":[]}],"tags":["llm"]}},"/api/sync/changed":{"get":{"summary":"Pull sync changes","operationId":"sync-changed","externalDocs":{"description":"Server implementation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts"},"parameters":[{"in":"query","name":"instanceId","required":true,"schema":{"type":"string"},"description":"Local instance ID"},{"in":"query","name":"lastEntityChangeId","required":true,"schema":{"type":"integer"},"description":"Last locally present change ID"},{"in":"query","name":"logMarkerId","required":true,"schema":{"type":"string"},"description":"Marker to identify this request in server log"}],"responses":{"200":{"description":"Sync changes, limited to approximately one megabyte.","content":{"application/json":{"schema":{"type":"object","properties":{"entityChanges":{"type":"array","items":{"$ref":"#/components/schemas/EntityChange"}},"lastEntityChangeId":{"type":"integer","description":"If `outstandingPullCount > 0`, pass this as parameter in your next request to continue."},"outstandingPullCount":{"type":"integer","example":42,"description":"Number of changes not yet returned by the remote."}}}}}}},"security":[{"session":[]}],"tags":["sync"]}},"/api/sync/update":{"put":{"summary":"Push sync changes","description":"Basic usage: set `pageCount = 1`, `pageIndex = 0`, and omit `requestId`. Supply your entity changes in the request body.","operationId":"sync-update","externalDocs":{"description":"Server implementation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/sync.ts"},"parameters":[{"in":"header","name":"pageCount","required":true,"schema":{"type":"integer"}},{"in":"header","name":"pageIndex","required":true,"schema":{"type":"integer"}},{"in":"header","name":"requestId","schema":{"type":"string","description":"ID to identify paginated requests"}},{"in":"query","name":"logMarkerId","required":true,"schema":{"type":"string"},"description":"Marker to identify this request in server log"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"instanceId":{"type":"string","description":"Local instance ID"},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityChange"}}}}}}},"responses":{"200":{"description":"Changes processed successfully"}},"security":[{"session":[]}],"tags":["sync"]}},"/api/tree":{"get":{"summary":"Retrieve tree data","operationId":"tree","externalDocs":{"description":"Server implementation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/api/tree.ts"},"parameters":[{"in":"query","name":"subTreeNoteId","required":false,"schema":{"type":"string"},"description":"Limit tree data to this note and descendants"}],"responses":{"200":{"description":"Notes, branches and attributes","content":{"application/json":{"schema":{"type":"object","properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/Branch"}},"notes":{"type":"array","items":{"$ref":"#/components/schemas/Note"}},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/Attribute"}}}}}}}},"security":[{"session":[]}],"tags":["data"]}},"/login":{"post":{"tags":["auth"],"summary":"Log in using password","description":"This will give you a Trilium session, which is required for some other API endpoints. `totpToken` is only required if the user configured TOTP authentication.","operationId":"login-normal","externalDocs":{"description":"HMAC calculation","url":"https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/utils.ts#L62-L66"},"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["password"],"properties":{"password":{"type":"string"},"totpToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Successful operation"},"401":{"description":"Password / TOTP mismatch"}}}}},"components":{"schemas":{"Attribute":{"type":"object","properties":{"attributeId":{"type":"string","example":"4G1DPrI58PAb"},"noteId":{"$ref":"#/components/schemas/NoteId"},"type":{"type":"string","enum":["label","relation"]},"name":{"type":"string","example":"internalLink"},"value":{"type":"string","example":"hA8aHSpTRdZ6","description":"If type = \"relation\", a note ID. Otherwise, the attribute content."},"position":{"type":"integer","example":20},"isInheritable":{"type":"boolean"}}},"Blob":{"type":"object","properties":{"blobId":{"type":"string","example":"8iqMIB8eiY1tPYmElfjm"},"content":{"type":["string","null"],"description":"`null` if not text."},"contentLength":{"type":"integer"},"dateModified":{"$ref":"#/components/schemas/DateTime"},"utcDateModified":{"$ref":"#/components/schemas/UtcDateTime"}}},"Branch":{"type":"object","required":["branchId","noteId","parentNoteId","notePosition"],"properties":{"branchId":{"$ref":"#/components/schemas/BranchId"},"noteId":{"$ref":"#/components/schemas/NoteId"},"parentNoteId":{"$ref":"#/components/schemas/NoteId"},"notePosition":{"type":"integer","example":20},"prefix":{"type":["string","null"]},"isExpanded":{"type":"boolean"}}},"BranchId":{"type":"string","example":"WUjhaGp4EKah_ur11rSfHkzeV","description":"Equal to `{parentNoteId}_{noteId}`"},"DateTime":{"type":"string","example":"2025-02-14 08:19:59.203+0100"},"EntityChange":{"type":"object","properties":{"entityChange":{"type":"object","properties":{"entityName":{"type":"string","example":"notes","description":"Database table for this entity."},"changeId":{"type":"string","example":"changeId9630","description":"ID, referenced in `entity_changes` table."}}},"entity":{"type":"object","description":"Encoded entity data. Object has one property for each database column."}}},"Note":{"type":"object","required":["noteId","title","isProtected","type","mime","blobId"],"properties":{"noteId":{"$ref":"#/components/schemas/NoteId"},"title":{"type":"string"},"isProtected":{"type":"boolean"},"type":{"type":"string","example":"text","enum":["text","code","render","file","image","search","relationMap","book","noteMap","mermaid","canvas","webView","launcher","doc","contentWidget","mindMap","geoMap"],"description":"[Reference list](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/services/note_types.ts)"},"mime":{"type":"string","example":"text/html"},"blobId":{"type":"string","example":"z4PhNX7vuL3xVChQ1m2A"}}},"NoteId":{"type":"string","example":"ur11rSfHkzeV","description":"12-character note ID. Special values: \"none\"`, `\"root\"."},"Timestamps":{"type":"object","properties":{"dateCreated":{"$ref":"#/components/schemas/DateTime"},"dateModified":{"$ref":"#/components/schemas/DateTime"},"utcDateCreated":{"$ref":"#/components/schemas/UtcDateTime"},"utcDateModified":{"$ref":"#/components/schemas/UtcDateTime"}}},"UtcDateTime":{"type":"string","example":"2025-02-13T07:42:47.698Z","description":"Result of `new Date().toISOString().replace('T', ' ')`"}},"securitySchemes":{"user-password":{"type":"apiKey","name":"trilium-cred","in":"header","description":"Username and password, formatted as `user:password`"},"session":{"type":"apiKey","in":"cookie","name":"trilium.sid"}}},"tags":[{"name":"auth","description":"Authentication"},{"name":"sync","description":"Synchronization"},{"name":"data"}]} \ No newline at end of file diff --git a/apps/server/src/routes/api_docs.ts b/apps/server/src/routes/api_docs.ts index 4b0b9f0ca..df39f3d61 100644 --- a/apps/server/src/routes/api_docs.ts +++ b/apps/server/src/routes/api_docs.ts @@ -3,22 +3,14 @@ import swaggerUi from "swagger-ui-express"; import { join } from "path"; import yaml from "js-yaml"; import type { JsonObject } from "swagger-ui-express"; -import { readFileSync, existsSync } from "fs"; +import { readFileSync } from "fs"; import { RESOURCE_DIR } from "../services/resource_dir"; export default function register(app: Application) { const etapiDocument = yaml.load(readFileSync(join(RESOURCE_DIR, "etapi.openapi.yaml"), "utf8")) as JsonObject; - // Load the comprehensive API documentation (YAML) if available, otherwise fall back to JSON - const apiYamlPath = join(RESOURCE_DIR, "api-openapi.yaml"); - const apiJsonPath = join(RESOURCE_DIR, "openapi.json"); - - let apiDocument: JsonObject; - if (existsSync(apiYamlPath)) { - apiDocument = yaml.load(readFileSync(apiYamlPath, "utf8")) as JsonObject; - } else { - apiDocument = JSON.parse(readFileSync(apiJsonPath, "utf-8")); - } + // Load the comprehensive API documentation from YAML + const apiDocument = yaml.load(readFileSync(join(RESOURCE_DIR, "api-openapi.yaml"), "utf8")) as JsonObject; app.use( "/etapi/docs/",