mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			feat/clean
			...
			kev/share-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 63c54010eb | ||
|  | cec868459a | 
| @@ -35,7 +35,7 @@ | ||||
|     "chore:generate-openapi": "tsx bin/generate-openapi.js" | ||||
|   }, | ||||
|   "devDependencies": {     | ||||
|     "@playwright/test": "1.56.0", | ||||
|     "@playwright/test": "1.55.1", | ||||
|     "@stylistic/eslint-plugin": "5.4.0",         | ||||
|     "@types/express": "5.0.3",     | ||||
|     "@types/node": "22.18.8",     | ||||
|   | ||||
| @@ -3,7 +3,16 @@ import linkContextMenuService from "../menus/link_context_menu.js"; | ||||
| import appContext, { type NoteCommandData } from "../components/app_context.js"; | ||||
| import froca from "./froca.js"; | ||||
| import utils from "./utils.js"; | ||||
| import { ALLOWED_PROTOCOLS } from "@triliumnext/commons"; | ||||
|  | ||||
| // Be consistent with `allowedSchemes` in `src\services\html_sanitizer.ts` | ||||
| // TODO: Deduplicate with server once we can. | ||||
| export const ALLOWED_PROTOCOLS = [ | ||||
|     'http', 'https', 'ftp', 'ftps', 'mailto', 'data', 'evernote', 'file', 'facetime', 'gemini', 'git', | ||||
|     'gopher', 'imap', 'irc', 'irc6', 'jabber', 'jar', 'lastfm', 'ldap', 'ldaps', 'magnet', 'message', | ||||
|     'mumble', 'nfs', 'onenote', 'pop', 'rmi', 's3', 'sftp', 'skype', 'sms', 'spotify', 'steam', 'svn', 'udp', | ||||
|     'view-source', 'vlc', 'vnc', 'ws', 'wss', 'xmpp', 'jdbc', 'slack', 'tel', 'smb', 'zotero', 'geo', | ||||
|     'mid' | ||||
| ]; | ||||
|  | ||||
| function getNotePathFromUrl(url: string) { | ||||
|     const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url); | ||||
|   | ||||
| @@ -1743,17 +1743,9 @@ | ||||
|     "show_login_link": "在共享主题中显示登录链接", | ||||
|     "show_login_link_description": "在共享页面底部添加登录链接", | ||||
|     "check_share_root": "检查共享根状态", | ||||
|     "check_share_root_error": "检查共享根状态时发生意外错误,请检查日志以获取更多信息。", | ||||
|     "share_note_title": "'{{noteTitle}}'", | ||||
|     "share_root_found": "共享根笔记 '{{noteTitle}}' 已准备好", | ||||
|     "share_root_not_found": "未找到带有 #shareRoot 标签的笔记", | ||||
|     "share_root_not_shared": "笔记 '{{noteTitle}}' 具有 #shareRoot 标签,但未共享", | ||||
|     "share_root_multiple_found": "找到多个具有 #shareRoot 标签的共享笔记:{{- foundNoteTitles}}。将使用笔记 {{- activeNoteTitle}} 作为共享根笔记。", | ||||
|     "share_path": "共享路径", | ||||
|     "share_path_description": "共享笔记的 URL 前缀(例如 '/share' --> '/share/noteId' 或 '/custom-path' --> '/custom-path/noteId')。支持多级嵌套(例如 '/custom-path/sub-path' --> '/custom-path/sub-path/noteId')。刷新页面以应用更改。", | ||||
|     "share_path_placeholder": "/share 或 /custom-path", | ||||
|     "share_subtree": "共享子树", | ||||
|     "share_subtree_description": "共享整个子树,而不是仅共享笔记" | ||||
|     "share_root_not_shared": "笔记 '{{noteTitle}}' 具有 #shareRoot 标签,但未共享" | ||||
|   }, | ||||
|   "time_selector": { | ||||
|     "invalid_input": "输入的时间值不是有效数字。", | ||||
|   | ||||
| @@ -1907,17 +1907,9 @@ | ||||
|     "show_login_link": "Show Login link in Share theme", | ||||
|     "show_login_link_description": "Add a login link to the Share page footer", | ||||
|     "check_share_root": "Check Share Root Status", | ||||
|     "check_share_root_error": "An unexpected error happened while checking the Share Root Status, please check the logs for more information.", | ||||
|     "share_note_title": "'{{noteTitle}}'", | ||||
|     "share_root_found": "Share root note '{{noteTitle}}' is ready", | ||||
|     "share_root_not_found": "No note with #shareRoot label found", | ||||
|     "share_root_not_shared": "Note '{{noteTitle}}' has #shareRoot label but is not Shared", | ||||
|     "share_root_multiple_found": "Found multiple shared notes with a #shareRoot label: {{- foundNoteTitles}}. The note {{- activeNoteTitle}} will be used as shared root note.", | ||||
|     "share_path": "Share path", | ||||
|     "share_path_description": "The url prefix for shared notes (e.g. '/share' --> '/share/noteId' or '/custom-path' --> '/custom-path/noteId'). Multiple levels of nesting are supported (e.g. '/custom-path/sub-path' --> '/custom-path/sub-path/noteId'). Refresh the page to apply the changes.", | ||||
|     "share_path_placeholder": "/share or /custom-path", | ||||
|     "share_subtree": "Share subtree", | ||||
|     "share_subtree_description": "Share the entire subtree, not just the note" | ||||
|     "share_root_not_shared": "Note '{{noteTitle}}' has #shareRoot label but is not shared" | ||||
|   }, | ||||
|   "time_selector": { | ||||
|     "invalid_input": "The entered time value is not a valid number.", | ||||
|   | ||||
| @@ -251,12 +251,12 @@ | ||||
|   "help": { | ||||
|     "title": "チートシート", | ||||
|     "noteNavigation": "ノートナビゲーション", | ||||
|     "collapseExpand": "ノードを折りたたむ / 展開", | ||||
|     "collapseExpand": "ノードの格納/展開", | ||||
|     "goBackForwards": "履歴を戻る/進む", | ||||
|     "scrollToActiveNote": "アクティブノートまでスクロール", | ||||
|     "jumpToParentNote": "親ノートへ移動", | ||||
|     "collapseWholeTree": "すべてのノートツリーを折りたたむ", | ||||
|     "collapseSubTree": "サブツリーを折りたたむ", | ||||
|     "collapseWholeTree": "すべてのノートツリーを格納", | ||||
|     "collapseSubTree": "サブツリーを格納", | ||||
|     "tabShortcuts": "タブショートカット", | ||||
|     "newTabNoteLink": "ノートのリンクをクリックすると、新しいタブで開く", | ||||
|     "newTabWithActivationNoteLink": "ノートのリンクをクリックすると、新しいタブで開き、アクティブにします", | ||||
| @@ -515,9 +515,9 @@ | ||||
|   "book_properties": { | ||||
|     "grid": "グリッド", | ||||
|     "list": "リスト", | ||||
|     "collapse_all_notes": "すべてのノートを折りたたむ", | ||||
|     "collapse_all_notes": "すべてのノートを格納", | ||||
|     "expand_all_children": "すべての子を展開", | ||||
|     "collapse": "折りたたむ", | ||||
|     "collapse": "格納", | ||||
|     "expand": "展開", | ||||
|     "book_properties": "コレクションプロパティ", | ||||
|     "invalid_view_type": "無効なビュータイプ '{{type}}'", | ||||
|   | ||||
| @@ -1,6 +1 @@ | ||||
| { | ||||
|   "about": { | ||||
|     "title": "Acerca de \"Trillium Notes\"", | ||||
|     "app_version": "Versão da aplicação:" | ||||
|   } | ||||
| } | ||||
| {} | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { ALLOWED_PROTOCOLS, MIME_TYPE_AUTO } from "@triliumnext/commons"; | ||||
| import { ALLOWED_PROTOCOLS } from "../../../services/link.js"; | ||||
| import { MIME_TYPE_AUTO } from "@triliumnext/commons"; | ||||
| import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS } from "@triliumnext/ckeditor5"; | ||||
| import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; | ||||
| import options from "../../../services/options.js"; | ||||
|   | ||||
| @@ -1,13 +0,0 @@ | ||||
| // Ensure sharePath always starts with a single slash and does not end with (one or multiple) trailing slashes | ||||
| export function normalizeSharePathInput(sharePathInput: string) { | ||||
|     const REGEXP_STARTING_SLASH = /^\/+/g; | ||||
|     const REGEXP_TRAILING_SLASH = /\b\/+$/g; | ||||
|  | ||||
|     const normalizedSharePath = (!sharePathInput.startsWith("/") | ||||
|         ? `/${sharePathInput}` | ||||
|         : sharePathInput) | ||||
|         .replaceAll(REGEXP_TRAILING_SLASH, "") | ||||
|         .replaceAll(REGEXP_STARTING_SLASH, "/"); | ||||
|  | ||||
|     return normalizedSharePath; | ||||
| } | ||||
| @@ -1,58 +0,0 @@ | ||||
| import { describe, it, expect } from "vitest"; | ||||
| import { normalizeSharePathInput } from "./share_path_utils.js"; | ||||
|  | ||||
| type TestCase<T extends (...args: any) => any> = [ | ||||
|     desc: string, | ||||
|     fnParams: Parameters<T>, | ||||
|     expected: ReturnType<T> | ||||
| ]; | ||||
|  | ||||
| describe("ShareSettingsOptions", () => { | ||||
|  | ||||
|     describe("#normalizeSharePathInput", () => { | ||||
|  | ||||
|         const testCases: TestCase<typeof normalizeSharePathInput>[] = [ | ||||
|             [ | ||||
|                 "should handle multiple trailing '/' and remove them completely", | ||||
|                 ["/trailingtest////"], | ||||
|                 "/trailingtest" | ||||
|             ], | ||||
|             [ | ||||
|                 "should handle multiple starting '/' and replace them by a single '/'", | ||||
|                 ["////startingtest"], | ||||
|                 "/startingtest" | ||||
|             ], | ||||
|             [ | ||||
|                 "should handle multiple starting & trailing '/' and replace them by a single '/'", | ||||
|                 ["////startingAndTrailingTest///"], | ||||
|                 "/startingAndTrailingTest" | ||||
|             ], | ||||
|             [ | ||||
|                 "should not remove any '/' other than at the end or start of the input", | ||||
|                 ["/test/with/subpath"], | ||||
|                 "/test/with/subpath" | ||||
|             ], | ||||
|             [ | ||||
|                 "should prepend the string with a '/' if it does not start with one", | ||||
|                 ["testpath"], | ||||
|                 "/testpath" | ||||
|             ], | ||||
|             [ | ||||
|                 "should not change anything, if the string is a single '/'", | ||||
|                 ["/"], | ||||
|                 "/" | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|         testCases.forEach((testCase) => { | ||||
|             const [desc, fnParams, expected] = testCase; | ||||
|             it(desc, () => { | ||||
|                 const actual = normalizeSharePathInput(...fnParams); | ||||
|                 expect(actual).toStrictEqual(expected); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|  | ||||
|     }) | ||||
|  | ||||
| }) | ||||
| @@ -90,10 +90,6 @@ const config: ForgeConfig = { | ||||
|                     base: "org.electronjs.Electron2.BaseApp", | ||||
|                     baseVersion: "24.08", | ||||
|                     baseFlatpakref: "https://flathub.org/repo/flathub.flatpakrepo", | ||||
|                     finishArgs: [ | ||||
|                         "--socket=fallback-x11", | ||||
|                         "--socket=wayland" | ||||
|                     ], | ||||
|                     modules: [ | ||||
|                         { | ||||
|                             name: "zypak", | ||||
|   | ||||
							
								
								
									
										73
									
								
								apps/edit-docs/demo/!!!meta.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								apps/edit-docs/demo/!!!meta.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"formatVersion": 2, | ||||
| 	"appVersion": "0.99.1", | ||||
| 	"appVersion": "0.98.1", | ||||
| 	"files": [ | ||||
| 		{ | ||||
| 			"isClone": false, | ||||
| @@ -60,13 +60,6 @@ | ||||
| 							"value": "dayGridMonth", | ||||
| 							"isInheritable": false, | ||||
| 							"position": 40 | ||||
| 						}, | ||||
| 						{ | ||||
| 							"type": "relation", | ||||
| 							"name": "dateTemplate", | ||||
| 							"value": "bRQvb9VCkc3t", | ||||
| 							"isInheritable": false, | ||||
| 							"position": 50 | ||||
| 						} | ||||
| 					], | ||||
| 					"dataFileName": "Journal.dat", | ||||
| @@ -82,7 +75,7 @@ | ||||
| 					"title": "Trilium Demo", | ||||
| 					"notePosition": 20, | ||||
| 					"prefix": null, | ||||
| 					"isExpanded": false, | ||||
| 					"isExpanded": true, | ||||
| 					"type": "text", | ||||
| 					"mime": "text/html", | ||||
| 					"attributes": [ | ||||
| @@ -6040,68 +6033,6 @@ | ||||
| 							] | ||||
| 						} | ||||
| 					] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"isClone": false, | ||||
| 					"noteId": "fhNlr1V1o3d8", | ||||
| 					"notePath": [ | ||||
| 						"root", | ||||
| 						"fhNlr1V1o3d8" | ||||
| 					], | ||||
| 					"title": "Miscellaneous", | ||||
| 					"notePosition": 30, | ||||
| 					"prefix": null, | ||||
| 					"isExpanded": false, | ||||
| 					"type": "text", | ||||
| 					"mime": "text/html", | ||||
| 					"attributes": [ | ||||
| 						{ | ||||
| 							"type": "label", | ||||
| 							"name": "iconClass", | ||||
| 							"value": "bx bx-dots-horizontal-rounded", | ||||
| 							"isInheritable": false, | ||||
| 							"position": 10 | ||||
| 						} | ||||
| 					], | ||||
| 					"format": "html", | ||||
| 					"attachments": [], | ||||
| 					"dirFileName": "Miscellaneous", | ||||
| 					"children": [ | ||||
| 						{ | ||||
| 							"isClone": false, | ||||
| 							"noteId": "bRQvb9VCkc3t", | ||||
| 							"notePath": [ | ||||
| 								"root", | ||||
| 								"fhNlr1V1o3d8", | ||||
| 								"bRQvb9VCkc3t" | ||||
| 							], | ||||
| 							"title": "Day Note Template", | ||||
| 							"notePosition": 10, | ||||
| 							"prefix": null, | ||||
| 							"isExpanded": false, | ||||
| 							"type": "text", | ||||
| 							"mime": "text/html", | ||||
| 							"attributes": [ | ||||
| 								{ | ||||
| 									"type": "label", | ||||
| 									"name": "iconClass", | ||||
| 									"value": "bx bx-notepad", | ||||
| 									"isInheritable": false, | ||||
| 									"position": 10 | ||||
| 								}, | ||||
| 								{ | ||||
| 									"type": "label", | ||||
| 									"name": "excludeFromNoteMap", | ||||
| 									"value": "", | ||||
| 									"isInheritable": false, | ||||
| 									"position": 20 | ||||
| 								} | ||||
| 							], | ||||
| 							"format": "html", | ||||
| 							"dataFileName": "Day Note Template.html", | ||||
| 							"attachments": [] | ||||
| 						} | ||||
| 					] | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
|   | ||||
							
								
								
									
										6
									
								
								apps/edit-docs/demo/navigation.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								apps/edit-docs/demo/navigation.html
									
									
									
									
										vendored
									
									
								
							| @@ -637,12 +637,6 @@ | ||||
|               </li> | ||||
|             </ul> | ||||
|           </li> | ||||
|           <li>Miscellaneous | ||||
|             <ul> | ||||
|               <li><a href="root/Miscellaneous/Day%20Note%20Template.html" target="detail">Day Note Template</a> | ||||
|               </li> | ||||
|             </ul> | ||||
|           </li> | ||||
|         </ul> | ||||
|       </li> | ||||
|     </ul> | ||||
|   | ||||
| @@ -1,24 +0,0 @@ | ||||
| <html> | ||||
|    | ||||
|   <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <link rel="stylesheet" href="../../style.css"> | ||||
|     <base target="_parent"> | ||||
|     <title data-trilium-title>Day Note Template</title> | ||||
|   </head> | ||||
|    | ||||
|   <body> | ||||
|     <div class="content"> | ||||
|        <h1 data-trilium-h1>Day Note Template</h1> | ||||
|  | ||||
|       <div class="ck-content"> | ||||
|         <h2>☑️ Tasks</h2> | ||||
|         <ul> | ||||
|           <li data-list-item-id="e4b26220d6ce48997f1116dc1d1d83dc0">[…]</li> | ||||
|         </ul> | ||||
|       </div> | ||||
|     </div> | ||||
|   </body> | ||||
|  | ||||
| </html> | ||||
| @@ -23,18 +23,10 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 	alert("Hello world"); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| }</code></pre> | ||||
|         <p>For larger pieces of code it is better to use a code note, which uses | ||||
|           a fully-fledged code editor (CodeMirror). For an example of a code note, | ||||
|   | ||||
| @@ -18,10 +18,6 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # This script opens 4 terminal windows. | ||||
|  | ||||
|  | ||||
| @@ -30,38 +26,18 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| i="0" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| while [ $i -lt 4 ] | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| do | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     xterm & | ||||
|  | ||||
|  | ||||
| @@ -70,22 +46,10 @@ do | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     i=$[$i+1] | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| done</code></pre> | ||||
|       </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -110,7 +110,7 @@ | ||||
|     "multer": "2.0.2", | ||||
|     "normalize-strings": "1.1.1", | ||||
|     "ollama": "0.6.0", | ||||
|     "openai": "6.2.0", | ||||
|     "openai": "6.1.0", | ||||
|     "rand-token": "1.0.1", | ||||
|     "safe-compare": "1.1.4", | ||||
|     "sanitize-filename": "1.6.3", | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										11
									
								
								apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Sharing.html
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Sharing.html
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,7 +6,8 @@ class="image"> | ||||
|   <img style="aspect-ratio:1144/660;" src="Sharing_image.png" width="1144" | ||||
|   height="660"> | ||||
|   </figure> | ||||
|   <h2>Features, interaction and limitations</h2> | ||||
|    | ||||
| <h2>Features, interaction and limitations</h2> | ||||
|   <ul> | ||||
|     <li>Searching by note title.</li> | ||||
|     <li>Automatic dark/light mode based on the user's browser settings.</li> | ||||
| @@ -188,9 +189,11 @@ class="image"> | ||||
|         <img src="Sharing_share-single-note.png" alt="Share Note"> | ||||
|       </p> | ||||
|     </li> | ||||
|     <li><strong>Access the Shared Note</strong>: The link provided will open the | ||||
|       note in your browser. If your server is not configured with a public IP, | ||||
|       the URL will refer to <code>localhost (127.0.0.1)</code>.</li> | ||||
|     <li> | ||||
|       <p><strong>Access the Shared Note</strong>: The link provided will open the | ||||
|         note in your browser. If your server is not configured with a public IP, | ||||
|         the URL will refer to <code>localhost (127.0.0.1)</code>.</p> | ||||
|     </li> | ||||
|   </ol> | ||||
|   <h2>Sharing a note subtree</h2> | ||||
|   <p>When you share a note, you actually share the entire subtree of notes | ||||
|   | ||||
| @@ -1,26 +1,26 @@ | ||||
| { | ||||
|   "keyboard_actions": { | ||||
|     "back-in-note-history": "Navegar para a nota anterior no histórico", | ||||
|     "forward-in-note-history": "Navegar para a nota seguinte no histórico", | ||||
|     "forward-in-note-history": "Navegar para a próxima nota no histórico", | ||||
|     "open-jump-to-note-dialog": "Abrir diálogo \"Ir para nota\"", | ||||
|     "open-command-palette": "Abrir paleta de comandos", | ||||
|     "scroll-to-active-note": "Rolar a árvore de notas até a nota atual", | ||||
|     "quick-search": "Ativar barra de pesquisa rápida", | ||||
|     "search-in-subtree": "Pesquisar notas na sub-árvore da nota atual", | ||||
|     "expand-subtree": "Expandir sub-árvore da nota atual", | ||||
|     "collapse-tree": "Colapsar a árvore de notas completa", | ||||
|     "collapse-subtree": "Colapsar sub-árvore da nota atual", | ||||
|     "search-in-subtree": "Pesquisar notas na subárvore da nota atual", | ||||
|     "expand-subtree": "Expandir subárvore da nota atual", | ||||
|     "collapse-tree": "Colapsar a árvore completa de notas", | ||||
|     "collapse-subtree": "Colapsar subárvore da nota atual", | ||||
|     "sort-child-notes": "Ordenar notas filhas", | ||||
|     "creating-and-moving-notes": "A criar e mover notas", | ||||
|     "create-note-after": "Criar nota após nota atual", | ||||
|     "create-note-into": "Criar nota como sub-nota da nota atual", | ||||
|     "create-note-into-inbox": "Criar uma nota na caixa de entrada (se definida) ou na nota do dia", | ||||
|     "create-note-into": "Criar nota como subnota da nota atual", | ||||
|     "create-note-into-inbox": "Crie uma nota na caixa de entrada (se definida) ou na nota do dia", | ||||
|     "delete-note": "Apagar nota", | ||||
|     "move-note-up": "Mover nota para cima", | ||||
|     "move-note-down": "Mover nota para baixo", | ||||
|     "move-note-up-in-hierarchy": "Mover nota para cima na hierarquia", | ||||
|     "move-note-down-in-hierarchy": "Mover nota para baixo na hierarquia", | ||||
|     "edit-note-title": "Saltar da árvore para os pormenores da nota e editar o título", | ||||
|     "edit-note-title": "Pular da árvore para os pormenores da nota e editar o título", | ||||
|     "edit-branch-prefix": "Exibir o diálogo \"Editar prefixo da ramificação\"", | ||||
|     "clone-notes-to": "Clonar notas selecionadas", | ||||
|     "move-notes-to": "Mover notas selecionadas", | ||||
| @@ -31,36 +31,36 @@ | ||||
|     "select-all-notes-in-parent": "Selecionar todas as notas do nível atual da nota", | ||||
|     "add-note-above-to-the-selection": "Adicionar nota acima à seleção", | ||||
|     "add-note-below-to-selection": "Adicionar nota abaixo à seleção", | ||||
|     "duplicate-subtree": "Duplicar subárvore", | ||||
|     "tabs-and-windows": "Separadores & Janelas", | ||||
|     "open-new-tab": "Abre novo separador", | ||||
|     "close-active-tab": "Fechar separador ativo", | ||||
|     "reopen-last-tab": "Reabre o último separador fechado", | ||||
|     "activate-next-tab": "Ativa separador à direita", | ||||
|     "activate-previous-tab": "Ativa separador à esquerda", | ||||
|     "duplicate-subtree": "Duplicar subárvores", | ||||
|     "tabs-and-windows": "Guias & Janelas", | ||||
|     "open-new-tab": "Abre nova guia", | ||||
|     "close-active-tab": "Fecha guia ativa", | ||||
|     "reopen-last-tab": "Reabre a última guia fechada", | ||||
|     "activate-next-tab": "Ativa guia à direita", | ||||
|     "activate-previous-tab": "Ativa guia à esquerda", | ||||
|     "open-new-window": "Abre nova janela vazia", | ||||
|     "toggle-tray": "Mostrar/ocultar a aplicação na bandeja do sistema", | ||||
|     "first-tab": "Ativar o primeiro separador na lista", | ||||
|     "second-tab": "Ativa o segundo separador na lista", | ||||
|     "third-tab": "Ativar o terceiro separador na lista", | ||||
|     "fourth-tab": "Ativar o quarto separador na lista", | ||||
|     "fifth-tab": "Ativar o quinto separador na lista", | ||||
|     "sixth-tab": "Ativar o sexto separador na lista", | ||||
|     "seventh-tab": "Ativar o sétimo separador na lista", | ||||
|     "eight-tab": "Ativar o oitavo separador na lista", | ||||
|     "ninth-tab": "Ativar o novo separador na lista", | ||||
|     "last-tab": "Ativar o último separador na lista", | ||||
|     "toggle-tray": "Mostrar/ocultar a aplicação da bandeja do sistema", | ||||
|     "first-tab": "Ativa a primeira guia na lista", | ||||
|     "second-tab": "Ativa a segunda guia na lista", | ||||
|     "third-tab": "Ativa a terceira guia na lista", | ||||
|     "fourth-tab": "Ativa a quarta guia na lista", | ||||
|     "fifth-tab": "Ativa a quinta guia na lista", | ||||
|     "sixth-tab": "Ativa a sexta guia na lista", | ||||
|     "seventh-tab": "Ativa a sétima guia na lista", | ||||
|     "eight-tab": "Ativa a oitava guia na lista", | ||||
|     "ninth-tab": "Ativa a nona guia na lista", | ||||
|     "last-tab": "Ativa a última guia na lista", | ||||
|     "dialogs": "Diálogos", | ||||
|     "show-note-source": "Exibe o diálogo \"origem da nota\"", | ||||
|     "show-options": "Abrir página de configurações", | ||||
|     "show-revisions": "Exibe diálogo \"revisões de nota\"", | ||||
|     "show-recent-changes": "Exibe o diálogo \"alterações recentes\"", | ||||
|     "show-sql-console": "Exibe a página \"consola SQL\"", | ||||
|     "show-backend-log": "Exibe a página \"registo do backend\"", | ||||
|     "show-help": "Exibir o guia de utilizador integrado", | ||||
|     "show-cheatsheet": "Exibir um modal com atalhos de teclado", | ||||
|     "show-note-source": "Exibe o diálogo de origem da nota", | ||||
|     "show-options": "Mostrar página de configurações", | ||||
|     "show-revisions": "Exibe diálogo de revisões de nota", | ||||
|     "show-recent-changes": "Exibe o diálogo de alterações recentes", | ||||
|     "show-sql-console": "Exibe a página do console SQL", | ||||
|     "show-backend-log": "Exibe a página do backend", | ||||
|     "show-help": "Exibir Ajuda integrada / colinha", | ||||
|     "show-cheatsheet": "Exibir um modal com operações comuns de teclado", | ||||
|     "text-note-operations": "Operações de nota de texto", | ||||
|     "add-link-to-text": "Abrir diálogo para adicionar ligação ao texto", | ||||
|     "add-link-to-text": "Abrir diálogo e adicionar ligação ao texto", | ||||
|     "follow-link-under-cursor": "Seguir a ligação sob o cursor", | ||||
|     "insert-date-and-time-to-text": "Inserir data e hora atual no texto", | ||||
|     "paste-markdown-into-text": "Colar Markdown da área de transferência na nota de texto", | ||||
|   | ||||
| @@ -16,8 +16,7 @@ vi.mock("../../services/ws.js", () => ({ | ||||
|     default: { | ||||
|         sendMessageToAllClients: vi.fn(), | ||||
|         sendTransactionEntityChangesToAllClients: vi.fn(), | ||||
|         setLastSyncedPush: vi.fn(), | ||||
|         syncFailed() {} | ||||
|         setLastSyncedPush: vi.fn() | ||||
|     } | ||||
| })); | ||||
|  | ||||
| @@ -82,7 +81,7 @@ async function loginWithSession(app: Application) { | ||||
|         .post("/login") | ||||
|         .send({ password: "demo1234" }) | ||||
|         .expect(302); | ||||
|  | ||||
|      | ||||
|     const setCookieHeader = response.headers["set-cookie"][0]; | ||||
|     expect(setCookieHeader).toBeTruthy(); | ||||
|     return setCookieHeader; | ||||
| @@ -92,14 +91,14 @@ async function loginWithSession(app: Application) { | ||||
| async function getCsrfToken(app: Application, sessionCookie: string) { | ||||
|     const response = await supertest(app) | ||||
|         .get("/") | ||||
|  | ||||
|          | ||||
|         .expect(200); | ||||
|  | ||||
|      | ||||
|     const csrfTokenMatch = response.text.match(/csrfToken: '([^']+)'/); | ||||
|     if (csrfTokenMatch) { | ||||
|         return csrfTokenMatch[1]; | ||||
|     } | ||||
|  | ||||
|      | ||||
|     throw new Error("CSRF token not found in response"); | ||||
| } | ||||
|  | ||||
| @@ -155,7 +154,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             expect(response.body).toHaveProperty('sessions'); | ||||
|             expect(Array.isArray(response.body.sessions)).toBe(true); | ||||
|  | ||||
|              | ||||
|             if (response.body.sessions.length > 0) { | ||||
|                 expect(response.body.sessions[0]).toMatchObject({ | ||||
|                     id: expect.any(String), | ||||
| @@ -172,18 +171,18 @@ describe("LLM API Tests", () => { | ||||
|                 // Create a chat first if we don't have one | ||||
|                 const createResponse = await supertest(app) | ||||
|                     .post("/api/llm/chat") | ||||
|  | ||||
|                      | ||||
|                     .send({ | ||||
|                         title: "Test Retrieval Chat" | ||||
|                     }) | ||||
|                     .expect(200); | ||||
|  | ||||
|                  | ||||
|                 createdChatId = createResponse.body.id; | ||||
|             } | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .get(`/api/llm/chat/${createdChatId}`) | ||||
|  | ||||
|                  | ||||
|                 .expect(200); | ||||
|  | ||||
|             expect(response.body).toMatchObject({ | ||||
| @@ -203,7 +202,7 @@ describe("LLM API Tests", () => { | ||||
|                         title: "Test Update Chat" | ||||
|                     }) | ||||
|                     .expect(200); | ||||
|  | ||||
|                  | ||||
|                 createdChatId = createResponse.body.id; | ||||
|             } | ||||
|  | ||||
| @@ -225,7 +224,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should return 404 for non-existent chat session", async () => { | ||||
|             await supertest(app) | ||||
|                 .get("/api/llm/chat/nonexistent-chat-id") | ||||
|  | ||||
|                  | ||||
|                 .expect(404); | ||||
|         }); | ||||
|     }); | ||||
| @@ -241,7 +240,7 @@ describe("LLM API Tests", () => { | ||||
|                     title: "Message Test Chat" | ||||
|                 }) | ||||
|                 .expect(200); | ||||
|  | ||||
|              | ||||
|             testChatId = createResponse.body.id; | ||||
|         }); | ||||
|  | ||||
| @@ -261,10 +260,10 @@ describe("LLM API Tests", () => { | ||||
|             // The response depends on whether AI is actually configured | ||||
|             // We should get either a successful response or an error about AI not being configured | ||||
|             expect([200, 400, 500]).toContain(response.status); | ||||
|  | ||||
|              | ||||
|             // All responses should have some body | ||||
|             expect(response.body).toBeDefined(); | ||||
|  | ||||
|              | ||||
|             // Either success with response or error | ||||
|             if (response.body.response) { | ||||
|                 expect(response.body).toMatchObject({ | ||||
| @@ -311,10 +310,10 @@ describe("LLM API Tests", () => { | ||||
|         beforeEach(async () => { | ||||
|             // Reset all mocks | ||||
|             vi.clearAllMocks(); | ||||
|  | ||||
|              | ||||
|             // Import options service to access mock | ||||
|             const options = (await import("../../services/options.js")).default; | ||||
|  | ||||
|              | ||||
|             // Setup default mock behaviors | ||||
|             (options.getOptionBool as any).mockReturnValue(true); // AI enabled | ||||
|             mockAiServiceManager.getOrCreateAnyService.mockResolvedValue({}); | ||||
| @@ -322,7 +321,7 @@ describe("LLM API Tests", () => { | ||||
|                 model: 'test-model', | ||||
|                 provider: 'test-provider' | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             // Create a fresh chat for each test | ||||
|             const mockChat = { | ||||
|                 id: 'streaming-test-chat', | ||||
| @@ -332,15 +331,15 @@ describe("LLM API Tests", () => { | ||||
|             }; | ||||
|             mockChatStorage.createChat.mockResolvedValue(mockChat); | ||||
|             mockChatStorage.getChat.mockResolvedValue(mockChat); | ||||
|  | ||||
|              | ||||
|             const createResponse = await supertest(app) | ||||
|                 .post("/api/llm/chat") | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     title: "Streaming Test Chat" | ||||
|                 }) | ||||
|                 .expect(200); | ||||
|  | ||||
|              | ||||
|             testChatId = createResponse.body.id; | ||||
|         }); | ||||
|  | ||||
| @@ -359,7 +358,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Tell me a short story", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -373,17 +372,17 @@ describe("LLM API Tests", () => { | ||||
|                 success: true, | ||||
|                 message: "Streaming initiated successfully" | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify WebSocket messages were sent | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
|                 chatNoteId: testChatId, | ||||
|                 thinking: undefined | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             // Verify streaming chunks were sent | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -391,7 +390,7 @@ describe("LLM API Tests", () => { | ||||
|                 content: 'Hello', | ||||
|                 done: false | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
|                 chatNoteId: testChatId, | ||||
| @@ -403,7 +402,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should handle empty content for streaming", async () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -420,7 +419,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should handle whitespace-only content for streaming", async () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "   \n\t   ", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -437,7 +436,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should handle invalid chat ID for streaming", async () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post("/api/llm/chat/invalid-chat-id/messages/stream") | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Hello", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -468,7 +467,7 @@ describe("LLM API Tests", () => { | ||||
|                 // Verify mention content is included | ||||
|                 expect(input.query).toContain('Tell me about this note'); | ||||
|                 expect(input.query).toContain('Root note content for testing'); | ||||
|  | ||||
|                  | ||||
|                 const callback = input.streamCallback; | ||||
|                 await callback('The root note contains', false, {}); | ||||
|                 await callback(' important information.', true, {}); | ||||
| @@ -476,7 +475,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Tell me about this note", | ||||
|                     useAdvancedContext: true, | ||||
| @@ -494,10 +493,10 @@ describe("LLM API Tests", () => { | ||||
|                 success: true, | ||||
|                 message: "Streaming initiated successfully" | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify thinking message was sent | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -518,7 +517,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "What is the meaning of life?", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -526,10 +525,10 @@ describe("LLM API Tests", () => { | ||||
|                 }); | ||||
|  | ||||
|             expect(response.status).toBe(200); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify thinking messages | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -537,7 +536,7 @@ describe("LLM API Tests", () => { | ||||
|                 thinking: 'Analyzing the question...', | ||||
|                 done: false | ||||
|             }); | ||||
|  | ||||
|              | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
|                 chatNoteId: testChatId, | ||||
| @@ -565,7 +564,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "What is 2 + 2?", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -573,10 +572,10 @@ describe("LLM API Tests", () => { | ||||
|                 }); | ||||
|  | ||||
|             expect(response.status).toBe(200); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify tool execution message | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -598,7 +597,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "This will fail", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -606,10 +605,10 @@ describe("LLM API Tests", () => { | ||||
|                 }); | ||||
|  | ||||
|             expect(response.status).toBe(200); // Still returns 200 | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify error message was sent via WebSocket | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -626,7 +625,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Hello AI", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -634,10 +633,10 @@ describe("LLM API Tests", () => { | ||||
|                 }); | ||||
|  | ||||
|             expect(response.status).toBe(200); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify error message about AI being disabled | ||||
|             expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({ | ||||
|                 type: 'llm-stream', | ||||
| @@ -656,7 +655,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Save this response", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -681,10 +680,10 @@ describe("LLM API Tests", () => { | ||||
|             }); | ||||
|  | ||||
|             // Send multiple requests rapidly | ||||
|             const promises = Array.from({ length: 3 }, (_, i) => | ||||
|             const promises = Array.from({ length: 3 }, (_, i) =>  | ||||
|                 supertest(app) | ||||
|                     .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                      | ||||
|                     .send({ | ||||
|                         content: `Request ${i + 1}`, | ||||
|                         useAdvancedContext: false, | ||||
| @@ -693,7 +692,7 @@ describe("LLM API Tests", () => { | ||||
|             ); | ||||
|  | ||||
|             const responses = await Promise.all(promises); | ||||
|  | ||||
|              | ||||
|             // All should succeed | ||||
|             responses.forEach(response => { | ||||
|                 expect(response.status).toBe(200); | ||||
| @@ -717,7 +716,7 @@ describe("LLM API Tests", () => { | ||||
|  | ||||
|             const response = await supertest(app) | ||||
|                 .post(`/api/llm/chat/${testChatId}/messages/stream`) | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     content: "Generate large response", | ||||
|                     useAdvancedContext: false, | ||||
| @@ -725,10 +724,10 @@ describe("LLM API Tests", () => { | ||||
|                 }); | ||||
|  | ||||
|             expect(response.status).toBe(200); | ||||
|  | ||||
|              | ||||
|             // Import ws service to access mock | ||||
|             const ws = (await import("../../services/ws.js")).default; | ||||
|  | ||||
|              | ||||
|             // Verify multiple chunks were sent | ||||
|             const streamCalls = (ws.sendMessageToAllClients as any).mock.calls.filter( | ||||
|                 call => call[0].type === 'llm-stream' && call[0].content | ||||
| @@ -742,7 +741,7 @@ describe("LLM API Tests", () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post("/api/llm/chat") | ||||
|                 .set('Content-Type', 'application/json') | ||||
|  | ||||
|                  | ||||
|                 .send('{ invalid json }'); | ||||
|  | ||||
|             expect([400, 500]).toContain(response.status); | ||||
| @@ -751,7 +750,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should handle missing required fields", async () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post("/api/llm/chat") | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     // Missing required fields | ||||
|                 }); | ||||
| @@ -763,7 +762,7 @@ describe("LLM API Tests", () => { | ||||
|         it("should handle invalid parameter types", async () => { | ||||
|             const response = await supertest(app) | ||||
|                 .post("/api/llm/chat") | ||||
|  | ||||
|                  | ||||
|                 .send({ | ||||
|                     title: "Test Chat", | ||||
|                     temperature: "invalid", // Should be number | ||||
| @@ -787,4 +786,4 @@ describe("LLM API Tests", () => { | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
| }); | ||||
| @@ -97,8 +97,6 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([ | ||||
|     "allowedHtmlTags", | ||||
|     "redirectBareDomain", | ||||
|     "showLoginInShareTheme", | ||||
|     "shareSubtree", | ||||
|     "sharePath", | ||||
|     "splitEditorOrientation", | ||||
|     "seenCallToActions", | ||||
|  | ||||
|   | ||||
| @@ -80,7 +80,6 @@ const GET = "get", | ||||
|     DEL = "delete"; | ||||
|  | ||||
| function register(app: express.Application) { | ||||
|  | ||||
|     route(GET, "/", [auth.checkAuth, csrfMiddleware], indexRoute.index); | ||||
|     route(GET, "/login", [auth.checkAppInitialized, auth.checkPasswordSet], loginRoute.loginPage); | ||||
|     route(GET, "/set-password", [auth.checkAppInitialized, auth.checkPasswordNotSet], loginRoute.setPasswordPage); | ||||
|   | ||||
| @@ -37,26 +37,9 @@ function checkAuth(req: Request, res: Response, next: NextFunction) { | ||||
|             // Check if any note has the #shareRoot label | ||||
|             const shareRootNotes = attributes.getNotesWithLabel("shareRoot"); | ||||
|             if (shareRootNotes.length === 0) { | ||||
|                 // should this be a translation string? | ||||
|                 res.status(404).json({ message: "Share root not found. Please set up a note with #shareRoot label first." }); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Get the configured share path | ||||
|             const sharePath = options.getOption("sharePath") || '/share'; | ||||
|  | ||||
|             // Check if we're already at the share path to prevent redirect loops | ||||
|             if (req.path === sharePath || req.path.startsWith(`${sharePath}/`)) { | ||||
|                 log.info(`checkAuth: Already at share path, skipping redirect. Path: ${req.path}, SharePath: ${sharePath}`); | ||||
|                 next(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Redirect to the share path | ||||
|             log.info(`checkAuth: Redirecting to share path. From: ${req.path}, To: ${sharePath}`); | ||||
|             res.redirect(`${sharePath}/`); | ||||
|         } else { | ||||
|             res.redirect("login"); | ||||
|         } | ||||
|         res.redirect(hasRedirectBareDomain ? "share" : "login"); | ||||
|     } else if (currentTotpStatus !== lastAuthState.totpEnabled || currentSsoStatus !== lastAuthState.ssoEnabled) { | ||||
| @@ -98,6 +81,15 @@ function checkApiAuthOrElectron(req: Request, res: Response, next: NextFunction) | ||||
|     } | ||||
| } | ||||
|  | ||||
| function checkApiAuth(req: Request, res: Response, next: NextFunction) { | ||||
|     if (!req.session.loggedIn && !noAuthentication) { | ||||
|         console.warn(`Missing session with ID '${req.sessionID}'.`); | ||||
|         reject(req, res, "Logged in session not found"); | ||||
|     } else { | ||||
|         next(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function checkAppInitialized(req: Request, res: Response, next: NextFunction) { | ||||
|     if (!sqlInit.isDbInitialized()) { | ||||
|         res.redirect("setup"); | ||||
|   | ||||
| @@ -9,13 +9,13 @@ import { changeLanguage } from "./i18n.js"; | ||||
| import { deferred } from "./utils.js"; | ||||
|  | ||||
| describe("Hidden Subtree", () => { | ||||
|     beforeAll(async () => { | ||||
|         sql_init.initializeDb(); | ||||
|         await sql_init.dbReady; | ||||
|         cls.init(() => hiddenSubtreeService.checkHiddenSubtree()); | ||||
|     }); | ||||
|  | ||||
|     describe("Launcher movement persistence", () => { | ||||
|         beforeAll(async () => { | ||||
|             sql_init.initializeDb(); | ||||
|             await sql_init.dbReady; | ||||
|             cls.init(() => hiddenSubtreeService.checkHiddenSubtree()); | ||||
|         }); | ||||
|  | ||||
|         it("should persist launcher movement between visible and available after integrity check", () => { | ||||
|             // Move backend log to visible launchers. | ||||
|             const backendLogBranch = becca.getBranchFromChildAndParent("_lbBackendLog", "_lbAvailableLaunchers"); | ||||
| @@ -119,14 +119,4 @@ describe("Hidden Subtree", () => { | ||||
|             await done; | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe("Hidden subtree", () => { | ||||
|         it("cleans up exclude from note map at the root", async () => { | ||||
|             const hiddenSubtree = becca.getNoteOrThrow("_hidden"); | ||||
|             cls.init(() => hiddenSubtree.addLabel("excludeFromNoteMap")); | ||||
|             expect(hiddenSubtree.hasLabel("excludeFromNoteMap")).toBeTruthy(); | ||||
|             cls.init(() => hiddenSubtreeService.checkHiddenSubtree()); | ||||
|             expect(hiddenSubtree.hasLabel("excludeFromNoteMap")).toBeFalsy(); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -40,8 +40,8 @@ function buildHiddenSubtreeDefinition(helpSubtree: HiddenSubtreeItem[]): HiddenS | ||||
|         // we want to keep the hidden subtree always last, otherwise there will be problems with e.g., keyboard navigation | ||||
|         // over tree when it's in the middle | ||||
|         notePosition: 999_999_999, | ||||
|         enforceAttributes: true, | ||||
|         attributes: [ | ||||
|             { type: "label", name: "excludeFromNoteMap", isInheritable: true }, | ||||
|             { type: "label", name: "docName", value: "hidden" } | ||||
|         ], | ||||
|         children: [ | ||||
| @@ -441,15 +441,6 @@ function checkHiddenSubtreeRecursively(parentNoteId: string, item: HiddenSubtree | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Enforce attribute structure if needed. | ||||
|     if (item.enforceAttributes) { | ||||
|         for (const attribute of note.getAttributes()) { | ||||
|             if (!attrs.some(a => a.name === attribute.name)) { | ||||
|                 attribute.markAsDeleted(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (const attr of attrs) { | ||||
|         const attrId = note.noteId + "_" + attr.type.charAt(0) + attr.name; | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,17 @@ | ||||
| import sanitizeHtml from "sanitize-html"; | ||||
| import { sanitizeUrl } from "@braintree/sanitize-url"; | ||||
| import optionService from "./options.js"; | ||||
| import { ALLOWED_PROTOCOLS, SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons"; | ||||
| import { SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons"; | ||||
|  | ||||
| // Be consistent with `ALLOWED_PROTOCOLS` in `src\public\app\services\link.js` | ||||
| // TODO: Deduplicate with client once we can. | ||||
| export const ALLOWED_PROTOCOLS = [ | ||||
|     'http', 'https', 'ftp', 'ftps', 'mailto', 'data', 'evernote', 'file', 'facetime', 'gemini', 'git', | ||||
|     'gopher', 'imap', 'irc', 'irc6', 'jabber', 'jar', 'lastfm', 'ldap', 'ldaps', 'magnet', 'message', | ||||
|     'mumble', 'nfs', 'onenote', 'pop', 'rmi', 's3', 'sftp', 'skype', 'sms', 'spotify', 'steam', 'svn', 'udp', | ||||
|     'view-source', 'vlc', 'vnc', 'ws', 'wss', 'xmpp', 'jdbc', 'slack', 'tel', 'smb', 'zotero', 'geo', | ||||
|     'mid' | ||||
| ]; | ||||
|  | ||||
| // intended mainly as protection against XSS via import | ||||
| // secondarily, it (partly) protects against "CSS takeover" | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { describe, it, expect, vi, beforeEach } from 'vitest'; | ||||
| import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; | ||||
| import { StreamProcessor, createStreamHandler, processProviderStream, extractStreamStats, performProviderHealthCheck } from './stream_handler.js'; | ||||
| import type { StreamProcessingOptions, StreamChunk } from './stream_handler.js'; | ||||
| import type { StreamProcessingOptions, StreamChunk, ProviderStreamOptions } from './stream_handler.js'; | ||||
|  | ||||
| // Mock the log module | ||||
| vi.mock('../../log.js', () => ({ | ||||
| @@ -86,7 +86,7 @@ describe('StreamProcessor', () => { | ||||
|  | ||||
|         it('should handle callback errors gracefully', async () => { | ||||
|             const errorCallback = vi.fn().mockRejectedValue(new Error('Callback error')); | ||||
|  | ||||
|              | ||||
|             // Should not throw | ||||
|             await expect(StreamProcessor.sendChunkToCallback(errorCallback, 'test', false, {}, 1)) | ||||
|                 .resolves.toBeUndefined(); | ||||
| @@ -127,7 +127,7 @@ describe('StreamProcessor', () => { | ||||
|  | ||||
|         it('should handle final callback errors gracefully', async () => { | ||||
|             const errorCallback = vi.fn().mockRejectedValue(new Error('Final callback error')); | ||||
|  | ||||
|              | ||||
|             await expect(StreamProcessor.sendFinalCallback(errorCallback, 'test')) | ||||
|                 .resolves.toBeUndefined(); | ||||
|         }); | ||||
| @@ -297,8 +297,8 @@ describe('processProviderStream', () => { | ||||
|     it('should handle tool calls in stream', async () => { | ||||
|         const chunks = [ | ||||
|             { message: { content: 'Using tool...' } }, | ||||
|             { | ||||
|                 message: { | ||||
|             {  | ||||
|                 message: {  | ||||
|                     tool_calls: [ | ||||
|                         { id: 'call_1', function: { name: 'calculator', arguments: '{"x": 5}' } } | ||||
|                     ] | ||||
| @@ -573,8 +573,8 @@ describe('Streaming edge cases and concurrency', () => { | ||||
|     it('should handle mixed content and tool calls', async () => { | ||||
|         const chunks = [ | ||||
|             { message: { content: 'Let me calculate that...' } }, | ||||
|             { | ||||
|                 message: { | ||||
|             {  | ||||
|                 message: {  | ||||
|                     content: '', | ||||
|                     tool_calls: [{ id: '1', function: { name: 'calc' } }] | ||||
|                 } | ||||
| @@ -599,4 +599,4 @@ describe('Streaming edge cases and concurrency', () => { | ||||
|         expect(result.completeText).toBe('Let me calculate that...The answer is 42.'); | ||||
|         expect(result.toolCalls).toHaveLength(1); | ||||
|     }); | ||||
| }); | ||||
| }); | ||||
| @@ -196,10 +196,8 @@ const defaultOptions: DefaultOption[] = [ | ||||
|     }, | ||||
|  | ||||
|     // Share settings | ||||
|     { name: "sharePath", value: "/share", isSynced: true }, | ||||
|     { name: "redirectBareDomain", value: "false", isSynced: true }, | ||||
|     { name: "showLoginInShareTheme", value: "false", isSynced: true }, | ||||
|     { name: "shareSubtree", value: "false", isSynced: true }, | ||||
|  | ||||
|     // AI Options | ||||
|     { name: "aiEnabled", value: "false", isSynced: true }, | ||||
|   | ||||
| @@ -32,7 +32,7 @@ export function getContent(note: SNote) { | ||||
|     }; | ||||
|  | ||||
|     if (note.type === "text") { | ||||
|         renderText(result, note, relativePath); | ||||
|         renderText(result, note); | ||||
|     } else if (note.type === "code") { | ||||
|         renderCode(result); | ||||
|     } else if (note.type === "mermaid") { | ||||
| @@ -106,10 +106,10 @@ function renderText(result: Result, note: SNote) { | ||||
|  | ||||
|         if (result.content.includes(`<span class="math-tex">`)) { | ||||
|             result.header += ` | ||||
| <script src="${relativePath}${assetPath}/node_modules/katex/dist/katex.min.js"></script> | ||||
| <link rel="stylesheet" href="${relativePath}${assetPath}/node_modules/katex/dist/katex.min.css"> | ||||
| <script src="${relativePath}${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js"></script> | ||||
| <script src="${relativePath}${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js"></script> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/katex.min.js"></script> | ||||
| <link rel="stylesheet" href="../${assetPath}/node_modules/katex/dist/katex.min.css"> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js"></script> | ||||
| <script src="../${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js"></script> | ||||
| <script> | ||||
| document.addEventListener("DOMContentLoaded", function() { | ||||
|     renderMathInElement(document.getElementById('content')); | ||||
|   | ||||
| @@ -9,7 +9,6 @@ describe("Share API test", () => { | ||||
|     let cannotSetHeadersCount = 0; | ||||
|  | ||||
|     beforeAll(async () => { | ||||
|         vi.useFakeTimers(); | ||||
|         const buildApp = (await import("../app.js")).default; | ||||
|         app = await buildApp(); | ||||
|         app.use((err: unknown, req: Request, res: Response, next: NextFunction) => { | ||||
| @@ -44,39 +43,3 @@ describe("Share API test", () => { | ||||
|     }); | ||||
|  | ||||
| }); | ||||
|  | ||||
| describe("Share Routes - Asset Path Calculation", () => { | ||||
|     it("should calculate correct relative path depth for different share paths", () => { | ||||
|         // Helper function to simulate the path depth calculation | ||||
|         const calculateRelativePath = (sharePath: string) => { | ||||
|             const pathDepth = sharePath.split('/').filter(segment => segment.length > 0).length; | ||||
|             return '../'.repeat(pathDepth); | ||||
|         }; | ||||
|  | ||||
|         // Test single level path | ||||
|         expect(calculateRelativePath("/share")).toBe("../"); | ||||
|  | ||||
|         // Test double level path | ||||
|         expect(calculateRelativePath("/sharePath/test")).toBe("../../"); | ||||
|  | ||||
|         // Test triple level path | ||||
|         expect(calculateRelativePath("/my/custom/share")).toBe("../../../"); | ||||
|  | ||||
|         // Test root path | ||||
|         expect(calculateRelativePath("/")).toBe(""); | ||||
|  | ||||
|         // Test path with trailing slash | ||||
|         expect(calculateRelativePath("/share/")).toBe("../"); | ||||
|     }); | ||||
|  | ||||
|     it("should handle normalized share paths correctly", () => { | ||||
|         const calculateRelativePath = (sharePath: string) => { | ||||
|             const pathDepth = sharePath.split('/').filter(segment => segment.length > 0).length; | ||||
|             return '../'.repeat(pathDepth); | ||||
|         }; | ||||
|  | ||||
|         // Test the examples from the original TODO comment | ||||
|         expect(calculateRelativePath("/sharePath")).toBe("../"); | ||||
|         expect(calculateRelativePath("/sharePath/test")).toBe("../../"); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import safeCompare from "safe-compare"; | ||||
|  | ||||
| import type { Request, Response, Router, NextFunction } from "express"; | ||||
| import type { Request, Response, Router } from "express"; | ||||
|  | ||||
| import shaca from "./shaca/shaca.js"; | ||||
| import shacaLoader from "./shaca/shaca_loader.js"; | ||||
| @@ -139,21 +139,17 @@ function renderImageAttachment(image: SNote, res: Response, attachmentName: stri | ||||
| } | ||||
|  | ||||
| function register(router: Router) { | ||||
|         function renderNote(note: SNote, req: Request, res: Response) { | ||||
|         // Calculate the correct relative path depth based on the current request path | ||||
|         // We need to go up one level for each path segment in the request URL | ||||
|         const pathSegments = req.path.split('/').filter(segment => segment.length > 0); | ||||
|         const relativePath = '../'.repeat(pathSegments.length); | ||||
|  | ||||
|     function renderNote(note: SNote, req: Request, res: Response) { | ||||
|         if (!note) { | ||||
|             console.log("Unable to find note ", note); | ||||
|             res.status(404); | ||||
|             renderDefault(res, "404", { relativePath, t }); | ||||
|             renderDefault(res, "404"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!checkNoteAccess(note.noteId, req, res)) { | ||||
|             requestCredentials(res); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
| @@ -165,20 +161,18 @@ function register(router: Router) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const { header, content, isEmpty } = contentRenderer.getContent(note, relativePath); | ||||
|         const { header, content, isEmpty } = contentRenderer.getContent(note); | ||||
|         const subRoot = getSharedSubTreeRoot(note); | ||||
|         const showLoginInShareTheme = options.getOption("showLoginInShareTheme"); | ||||
|  | ||||
|         const opts = { | ||||
|             note, | ||||
|             header, | ||||
|             content, | ||||
|             isEmpty, | ||||
|             subRoot, | ||||
|             assetPath: isDev ? assetPath : `${relativePath}${assetPath}`, | ||||
|             assetPath: isDev ? assetPath : `../${assetPath}`, | ||||
|             assetUrlFragment, | ||||
|             appPath: isDev ? appPath : `${relativePath}${appPath}`, | ||||
|             relativePath, | ||||
|             appPath: isDev ? appPath : `../${appPath}`, | ||||
|             showLoginInShareTheme, | ||||
|             t, | ||||
|             isDev | ||||
| @@ -225,165 +219,184 @@ function register(router: Router) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Dynamic dispatch middleware | ||||
|     router.use((req: Request, res: Response, next: NextFunction) => { | ||||
|         const sharePath = options.getOptionOrNull("sharePath") || "/share"; | ||||
|         // Only handle requests starting with sharePath | ||||
|         if (req.path === sharePath || req.path.startsWith(sharePath + "/")) { | ||||
|             // Remove sharePath prefix to get the remaining path | ||||
|             const subPath = req.path.slice(sharePath.length); | ||||
|             // Handle root path | ||||
|             if (subPath === "" || subPath === "/") { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 if (!shaca.shareRootNote) { | ||||
|                     res.status(404).json({ message: "Share root not found" }); | ||||
|                     return; | ||||
|                 } | ||||
|                 renderNote(shaca.shareRootNote, req, res); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /:shareId | ||||
|             const shareIdMatch = subPath.match(/^\/([^/]+)$/); | ||||
|             if (shareIdMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const shareId = shareIdMatch[1]; | ||||
|                 const note = shaca.aliasToNote[shareId] || shaca.notes[shareId]; | ||||
|                 renderNote(note, req, res); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/notes/:noteId | ||||
|             const apiNoteMatch = subPath.match(/^\/api\/notes\/([^/]+)$/); | ||||
|             if (apiNoteMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const noteId = apiNoteMatch[1]; | ||||
|                 let note: SNote | boolean; | ||||
|                 if (!(note = checkNoteAccess(noteId, req, res))) return; | ||||
|                 addNoIndexHeader(note, res); | ||||
|                 res.json(note.getPojo()); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/notes/:noteId/download | ||||
|             const apiNoteDownloadMatch = subPath.match(/^\/api\/notes\/([^/]+)\/download$/); | ||||
|             if (apiNoteDownloadMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const noteId = apiNoteDownloadMatch[1]; | ||||
|                 let note: SNote | boolean; | ||||
|                 if (!(note = checkNoteAccess(noteId, req, res))) return; | ||||
|                 addNoIndexHeader(note, res); | ||||
|                 const filename = utils.formatDownloadTitle(note.title, note.type, note.mime); | ||||
|                 res.setHeader("Content-Disposition", utils.getContentDisposition(filename)); | ||||
|                 res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|                 res.setHeader("Content-Type", note.mime); | ||||
|                 res.send(note.getContent()); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/images/:noteId/:filename | ||||
|             const apiImageMatch = subPath.match(/^\/api\/images\/([^/]+)\/([^/]+)$/); | ||||
|             if (apiImageMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const noteId = apiImageMatch[1]; | ||||
|                 let image: SNote | boolean; | ||||
|                 if (!(image = checkNoteAccess(noteId, req, res))) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (image.type === "image") { | ||||
|                     // normal image | ||||
|                     res.set("Content-Type", image.mime); | ||||
|                     addNoIndexHeader(image, res); | ||||
|                     res.send(image.getContent()); | ||||
|                 } else if (image.type === "canvas") { | ||||
|                     renderImageAttachment(image, res, "canvas-export.svg"); | ||||
|                 } else if (image.type === "mermaid") { | ||||
|                     renderImageAttachment(image, res, "mermaid-export.svg"); | ||||
|                 } else if (image.type === "mindMap") { | ||||
|                     renderImageAttachment(image, res, "mindmap-export.svg"); | ||||
|                 } else { | ||||
|                     res.status(400).json({ message: "Requested note is not a shareable image" }); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/attachments/:attachmentId/image/:filename | ||||
|             const apiAttachmentImageMatch = subPath.match(/^\/api\/attachments\/([^/]+)\/image\/([^/]+)$/); | ||||
|             if (apiAttachmentImageMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const attachmentId = apiAttachmentImageMatch[1]; | ||||
|                 let attachment: SAttachment | boolean; | ||||
|                 if (!(attachment = checkAttachmentAccess(attachmentId, req, res))) { | ||||
|                     return; | ||||
|                 } | ||||
|                 if (attachment.role === "image") { | ||||
|                     res.set("Content-Type", attachment.mime); | ||||
|                     addNoIndexHeader(attachment.note, res); | ||||
|                     res.send(attachment.getContent()); | ||||
|                 } else { | ||||
|                     res.status(400).json({ message: "Requested attachment is not a shareable image" }); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/attachments/:attachmentId/download | ||||
|             const apiAttachmentDownloadMatch = subPath.match(/^\/api\/attachments\/([^/]+)\/download$/); | ||||
|             if (apiAttachmentDownloadMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const attachmentId = apiAttachmentDownloadMatch[1]; | ||||
|                 let attachment: SAttachment | boolean; | ||||
|                 if (!(attachment = checkAttachmentAccess(attachmentId, req, res))) { | ||||
|                     return; | ||||
|                 } | ||||
|                 addNoIndexHeader(attachment.note, res); | ||||
|                 const filename = utils.formatDownloadTitle(attachment.title, null, attachment.mime); | ||||
|                 res.setHeader("Content-Disposition", utils.getContentDisposition(filename)); | ||||
|                 res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|                 res.setHeader("Content-Type", attachment.mime); | ||||
|                 res.send(attachment.getContent()); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/notes/:noteId/view | ||||
|             const apiNoteViewMatch = subPath.match(/^\/api\/notes\/([^/]+)\/view$/); | ||||
|             if (apiNoteViewMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const noteId = apiNoteViewMatch[1]; | ||||
|                 let note: SNote | boolean; | ||||
|                 if (!(note = checkNoteAccess(noteId, req, res))) { | ||||
|                     return; | ||||
|                 } | ||||
|                 addNoIndexHeader(note, res); | ||||
|                 res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|                 res.setHeader("Content-Type", note.mime); | ||||
|                 res.send(note.getContent()); | ||||
|                 return; | ||||
|             } | ||||
|             // Handle /api/notes 搜索 | ||||
|             const apiNotesSearchMatch = subPath.match(/^\/api\/notes$/); | ||||
|             if (apiNotesSearchMatch) { | ||||
|                 shacaLoader.ensureLoad(); | ||||
|                 const ancestorNoteId = req.query.ancestorNoteId ?? "_share"; | ||||
|                 if (typeof ancestorNoteId !== "string") { | ||||
|                     res.status(400).json({ message: "'ancestorNoteId' parameter is mandatory." }); | ||||
|                     return; | ||||
|                 } | ||||
|                 // This will automatically return if no ancestorNoteId is provided and there is no shareIndex | ||||
|                 if (!checkNoteAccess(ancestorNoteId, req, res)) { | ||||
|                     return; | ||||
|                 } | ||||
|                 const { search } = req.query; | ||||
|                 if (typeof search !== "string" || !search?.trim()) { | ||||
|                     res.status(400).json({ message: "'search' parameter is mandatory." }); | ||||
|                     return; | ||||
|                 } | ||||
|                 const searchContext = new SearchContext({ ancestorNoteId: ancestorNoteId }); | ||||
|                 const searchResults = searchService.findResultsWithQuery(search, searchContext); | ||||
|                 const filteredResults = searchResults.map((sr) => { | ||||
|                     const fullNote = shaca.notes[sr.noteId]; | ||||
|                     const startIndex = sr.notePathArray.indexOf(ancestorNoteId); | ||||
|                     const localPathArray = sr.notePathArray.slice(startIndex + 1).filter((id) => shaca.notes[id]); | ||||
|                     const pathTitle = localPathArray.map((id) => shaca.notes[id].title).join(" / "); | ||||
|                     return { id: fullNote.shareId, title: fullNote.title, score: sr.score, path: pathTitle }; | ||||
|                 }); | ||||
|                 res.json({ results: filteredResults }); | ||||
|                 return; | ||||
|             } | ||||
|     router.get("/share/", (req, res) => { | ||||
|         if (req.path.substr(-1) !== "/") { | ||||
|             res.redirect("../share/"); | ||||
|             return; | ||||
|         } | ||||
|         next(); | ||||
|  | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         if (!shaca.shareRootNote) { | ||||
|             res.status(404).json({ message: "Share root note not found" }); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         renderNote(shaca.shareRootNote, req, res); | ||||
|     }); | ||||
|  | ||||
|     router.get("/share/:shareId", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         const { shareId } = req.params; | ||||
|  | ||||
|         const note = shaca.aliasToNote[shareId] || shaca.notes[shareId]; | ||||
|  | ||||
|         renderNote(note, req, res); | ||||
|     }); | ||||
|  | ||||
|     router.get("/share/api/notes/:noteId", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|         let note: SNote | boolean; | ||||
|  | ||||
|         if (!(note = checkNoteAccess(req.params.noteId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         addNoIndexHeader(note, res); | ||||
|  | ||||
|         res.json(note.getPojo()); | ||||
|     }); | ||||
|  | ||||
|     router.get("/share/api/notes/:noteId/download", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         let note: SNote | boolean; | ||||
|  | ||||
|         if (!(note = checkNoteAccess(req.params.noteId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         addNoIndexHeader(note, res); | ||||
|  | ||||
|         const filename = utils.formatDownloadTitle(note.title, note.type, note.mime); | ||||
|  | ||||
|         res.setHeader("Content-Disposition", utils.getContentDisposition(filename)); | ||||
|  | ||||
|         res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|         res.setHeader("Content-Type", note.mime); | ||||
|  | ||||
|         res.send(note.getContent()); | ||||
|     }); | ||||
|  | ||||
|     // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename | ||||
|     router.get("/share/api/images/:noteId/:filename", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         let image: SNote | boolean; | ||||
|  | ||||
|         if (!(image = checkNoteAccess(req.params.noteId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (image.type === "image") { | ||||
|             // normal image | ||||
|             res.set("Content-Type", image.mime); | ||||
|             addNoIndexHeader(image, res); | ||||
|             res.send(image.getContent()); | ||||
|         } else if (image.type === "canvas") { | ||||
|             renderImageAttachment(image, res, "canvas-export.svg"); | ||||
|         } else if (image.type === "mermaid") { | ||||
|             renderImageAttachment(image, res, "mermaid-export.svg"); | ||||
|         } else if (image.type === "mindMap") { | ||||
|             renderImageAttachment(image, res, "mindmap-export.svg"); | ||||
|         } else { | ||||
|             res.status(400).json({ message: "Requested note is not a shareable image" }); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename | ||||
|     router.get("/share/api/attachments/:attachmentId/image/:filename", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         let attachment: SAttachment | boolean; | ||||
|  | ||||
|         if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (attachment.role === "image") { | ||||
|             res.set("Content-Type", attachment.mime); | ||||
|             addNoIndexHeader(attachment.note, res); | ||||
|             res.send(attachment.getContent()); | ||||
|         } else { | ||||
|             res.status(400).json({ message: "Requested attachment is not a shareable image" }); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     router.get("/share/api/attachments/:attachmentId/download", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         let attachment: SAttachment | boolean; | ||||
|  | ||||
|         if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         addNoIndexHeader(attachment.note, res); | ||||
|  | ||||
|         const filename = utils.formatDownloadTitle(attachment.title, null, attachment.mime); | ||||
|  | ||||
|         res.setHeader("Content-Disposition", utils.getContentDisposition(filename)); | ||||
|  | ||||
|         res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|         res.setHeader("Content-Type", attachment.mime); | ||||
|  | ||||
|         res.send(attachment.getContent()); | ||||
|     }); | ||||
|  | ||||
|     // used for PDF viewing | ||||
|     router.get("/share/api/notes/:noteId/view", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         let note: SNote | boolean; | ||||
|  | ||||
|         if (!(note = checkNoteAccess(req.params.noteId, req, res))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         addNoIndexHeader(note, res); | ||||
|  | ||||
|         res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); | ||||
|         res.setHeader("Content-Type", note.mime); | ||||
|  | ||||
|         res.send(note.getContent()); | ||||
|     }); | ||||
|  | ||||
|     // Used for searching, require noteId so we know the subTreeRoot | ||||
|     router.get("/share/api/notes", (req, res) => { | ||||
|         shacaLoader.ensureLoad(); | ||||
|  | ||||
|         const ancestorNoteId = req.query.ancestorNoteId ?? "_share"; | ||||
|  | ||||
|         if (typeof ancestorNoteId !== "string") { | ||||
|             res.status(400).json({ message: "'ancestorNoteId' parameter is mandatory." }); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // This will automatically return if no ancestorNoteId is provided and there is no shareIndex | ||||
|         if (!checkNoteAccess(ancestorNoteId, req, res)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const { search } = req.query; | ||||
|  | ||||
|         if (typeof search !== "string" || !search?.trim()) { | ||||
|             res.status(400).json({ message: "'search' parameter is mandatory." }); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const searchContext = new SearchContext({ ancestorNoteId: ancestorNoteId }); | ||||
|         const searchResults = searchService.findResultsWithQuery(search, searchContext); | ||||
|         const filteredResults = searchResults.map((sr) => { | ||||
|             const fullNote = shaca.notes[sr.noteId]; | ||||
|             const startIndex = sr.notePathArray.indexOf(ancestorNoteId); | ||||
|             const localPathArray = sr.notePathArray.slice(startIndex + 1).filter((id) => shaca.notes[id]); | ||||
|             const pathTitle = localPathArray.map((id) => shaca.notes[id].title).join(" / "); | ||||
|             return { id: fullNote.shareId, title: fullNote.title, score: sr.score, path: pathTitle }; | ||||
|         }); | ||||
|  | ||||
|         res.json({ results: filteredResults }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| import utils from "../services/utils.js"; | ||||
| import BNote from "../becca/entities/bnote.js"; | ||||
| import BAttribute from "../becca/entities/battribute.js"; | ||||
| import BBranch from "../becca/entities/bbranch.js"; | ||||
|  | ||||
| type AttributeDefinitions = { [key in `#${string}`]: string; }; | ||||
| type RelationDefinitions = { [key in `~${string}`]: string; }; | ||||
| @@ -10,7 +9,6 @@ interface NoteDefinition extends AttributeDefinitions, RelationDefinitions { | ||||
|     id?: string | undefined; | ||||
|     title?: string; | ||||
|     content?: string; | ||||
|     children?: NoteDefinition[]; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -53,18 +51,6 @@ export function buildNote(noteDef: NoteDefinition) { | ||||
|         note.getContent = () => noteDef.content!; | ||||
|     } | ||||
|  | ||||
|     // Handle children | ||||
|     if (noteDef.children) { | ||||
|         for (const childDef of noteDef.children) { | ||||
|             const childNote = buildNote(childDef); | ||||
|             new BBranch({ | ||||
|                 noteId: childNote.noteId, | ||||
|                 parentNoteId: note.noteId, | ||||
|                 branchId: `${note.noteId}_${childNote.noteId}` | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Handle labels and relations. | ||||
|     let position = 0; | ||||
|     for (const [ key, value ] of Object.entries(noteDef)) { | ||||
|   | ||||
| @@ -27,6 +27,6 @@ export default defineConfig(() => ({ | ||||
|       provider: 'v8' as const, | ||||
|       reporter: [ "text", "html" ] | ||||
|     }, | ||||
|     pool: "vmForks" | ||||
|     pool: "threads" | ||||
|   }, | ||||
| })); | ||||
|   | ||||
							
								
								
									
										2
									
								
								docs/README-ro.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								docs/README-ro.md
									
									
									
									
										vendored
									
									
								
							| @@ -153,7 +153,7 @@ sugestii sau probleme aveți! | ||||
|  | ||||
| ## 🏗 Procesul de instalare | ||||
|  | ||||
| ### Windows / macOS | ||||
| ### Windows / MacOS | ||||
|  | ||||
| Descărcați release-ul binar pentru platforma dvs. de pe pagina [ultimului | ||||
| release](https://github.com/TriliumNext/Trilium/releases/latest), dezarhivați și | ||||
|   | ||||
| @@ -123,16 +123,6 @@ When accessing a share, the sub-notes will be displayed in a tree on the left. B | ||||
|  | ||||
| To do so, create a shared text note and apply the `shareIndex` label. When viewed, the list of shared roots will be displayed at the bottom of the note. | ||||
|  | ||||
| ### Redirect Bare Domain to Share Page | ||||
|  | ||||
| This option can be enabled under `Option → Other → Share Settings`. When activated, anonymous users accessing the bare domain will be redirected to the Share page, preventing them from seeing the login option and thereby improving security.   | ||||
| To ensure accessibility for legitimate users, you can also enable a login link on the Share page, allowing yourself to access the login screen if you're redirected there. | ||||
|  | ||||
| ### Setting a Custom Share Path | ||||
|  | ||||
| This option can be enabled under `Option → Other → Share Settings`. It allows you to customize the share URL prefix before the `noteId`. Nested paths are supported.   | ||||
| If you're using a proxy service, make sure to update its configuration accordingly to reflect the new path structure. | ||||
|  | ||||
| ## Attribute reference | ||||
|  | ||||
| <table><thead><tr><th>Attribute</th><th>Description</th></tr></thead><tbody><tr><td><code>shareHiddenFromTree</code></td><td>this note is hidden from left navigation tree, but still accessible with its URL</td></tr><tr><td><code>shareExternalLink</code></td><td>note will act as a link to an external website in the share tree</td></tr><tr><td><code>shareAlias</code></td><td>define an alias using which the note will be available under <code>https://your_trilium_host/share/[your_alias]</code></td></tr><tr><td><code>shareOmitDefaultCss</code></td><td>default share page CSS will be omitted. Use when you make extensive styling changes.</td></tr><tr><td><code>shareRoot</code></td><td>marks note which is served on /share root.</td></tr><tr><td><code>shareDescription</code></td><td>define text to be added to the HTML meta tag for description</td></tr><tr><td><code>shareRaw</code></td><td>Note will be served in its raw format, without HTML wrapper. See also <a class="reference-link" href="Sharing/Serving%20directly%20the%20content%20o.md">Serving directly the content of a note</a> for an alternative method without setting an attribute.</td></tr><tr><td><code>shareDisallowRobotIndexing</code></td><td><p>Indicates to web crawlers that the page should not be indexed of this note by:</p><ul><li data-list-item-id="e6baa9f60bf59d085fd31aa2cce07a0e7">Setting the <code>X-Robots-Tag: noindex</code> HTTP header.</li><li data-list-item-id="ec0d067db136ef9794e4f1033405880b7">Setting the <code>noindex, follow</code> meta tag.</li></ul></td></tr><tr><td><code>shareCredentials</code></td><td>require credentials to access this shared note. Value is expected to be in format <code>username:password</code>. Don't forget to make this inheritable to apply to child-notes/images.</td></tr><tr><td><code>shareIndex</code></td><td>Note with this label will list all roots of shared notes.</td></tr><tr><td><code>shareHtmlLocation</code></td><td>defines where custom HTML injected via <code>~shareHtml</code> relation should be placed. Applied to the HTML snippet note itself. Format: <code>location:position</code> where location is <code>head</code>, <code>body</code>, or <code>content</code> and position is <code>start</code> or <code>end</code>. Defaults to <code>content:end</code>.</td></tr></tbody></table> | ||||
|   | ||||
| @@ -200,7 +200,7 @@ | ||||
|           # '/build/source/apps/desktop/node_modules/better-sqlite3/build/node_gyp_bins' | ||||
|           preBuildCommands = '' | ||||
|             export npm_config_nodedir=${electron.headers} | ||||
|             pnpm postinstall | ||||
|             pnpm postinstall || true | ||||
|           ''; | ||||
|           buildTask = "desktop:build"; | ||||
|           mainProgram = "trilium"; | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
|   "private": true, | ||||
|   "devDependencies": { | ||||
|     "@electron/rebuild": "4.0.1", | ||||
|     "@playwright/test": "1.56.0", | ||||
|     "@playwright/test": "1.55.1", | ||||
|     "@triliumnext/server": "workspace:*", | ||||
|     "@types/express": "5.0.3", | ||||
|     "@types/node": "22.18.8", | ||||
| @@ -59,7 +59,7 @@ | ||||
|     "tslib": "2.8.1", | ||||
|     "tsx": "4.20.6", | ||||
|     "typescript": "~5.9.0", | ||||
|     "typescript-eslint": "8.46.0", | ||||
|     "typescript-eslint": "8.45.0", | ||||
|     "upath": "2.0.1", | ||||
|     "vite": "7.1.9", | ||||
|     "vite-plugin-dts": "~4.5.0", | ||||
| @@ -79,7 +79,7 @@ | ||||
|     "url": "https://github.com/TriliumNext/Trilium/issues" | ||||
|   }, | ||||
|   "homepage": "https://triliumnotes.org", | ||||
|   "packageManager": "pnpm@10.18.1", | ||||
|   "packageManager": "pnpm@10.18.0", | ||||
|   "pnpm": { | ||||
|     "patchedDependencies": { | ||||
|       "@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch", | ||||
| @@ -90,7 +90,7 @@ | ||||
|       "mermaid": "11.12.0", | ||||
|       "preact": "10.27.2", | ||||
|       "roughjs": "4.6.6", | ||||
|       "@types/express-serve-static-core": "5.1.0", | ||||
|       "@types/express-serve-static-core": "5.0.7", | ||||
|       "flat@<5.0.1": ">=5.0.1", | ||||
|       "debug@>=3.2.0 <3.2.7": ">=3.2.7", | ||||
|       "nanoid@<3.3.8": ">=3.3.8", | ||||
|   | ||||
| @@ -24,8 +24,8 @@ | ||||
|     "@ckeditor/ckeditor5-dev-build-tools": "43.1.0", | ||||
|     "@ckeditor/ckeditor5-inspector": ">=4.1.0", | ||||
|     "@ckeditor/ckeditor5-package-tools": "4.1.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "@vitest/browser": "3.2.4", | ||||
|     "@vitest/coverage-istanbul": "3.2.4", | ||||
|     "ckeditor5": "47.0.0", | ||||
|   | ||||
| @@ -25,8 +25,8 @@ | ||||
|     "@ckeditor/ckeditor5-dev-build-tools": "43.1.0", | ||||
|     "@ckeditor/ckeditor5-inspector": ">=4.1.0", | ||||
|     "@ckeditor/ckeditor5-package-tools": "4.1.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "@vitest/browser": "3.2.4", | ||||
|     "@vitest/coverage-istanbul": "3.2.4", | ||||
|     "ckeditor5": "47.0.0", | ||||
|   | ||||
| @@ -27,8 +27,8 @@ | ||||
|     "@ckeditor/ckeditor5-dev-build-tools": "43.1.0", | ||||
|     "@ckeditor/ckeditor5-inspector": ">=4.1.0", | ||||
|     "@ckeditor/ckeditor5-package-tools": "4.1.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "@vitest/browser": "3.2.4", | ||||
|     "@vitest/coverage-istanbul": "3.2.4", | ||||
|     "ckeditor5": "47.0.0", | ||||
|   | ||||
| @@ -28,8 +28,8 @@ | ||||
|     "@ckeditor/ckeditor5-dev-utils": "43.1.0", | ||||
|     "@ckeditor/ckeditor5-inspector": ">=4.1.0", | ||||
|     "@ckeditor/ckeditor5-package-tools": "4.1.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "@vitest/browser": "3.2.4", | ||||
|     "@vitest/coverage-istanbul": "3.2.4", | ||||
|     "ckeditor5": "47.0.0", | ||||
|   | ||||
| @@ -30,12 +30,7 @@ export default class MathCommand extends Command { | ||||
|  | ||||
| 				mathtex = writer.createElement( | ||||
| 					display ? 'mathtex-display' : 'mathtex-inline', | ||||
| 					{ | ||||
| 						...Object.fromEntries(selection.getAttributes()), | ||||
| 						equation, | ||||
| 						type, | ||||
| 						display | ||||
| 					} | ||||
| 					{ equation, type, display } | ||||
| 				); | ||||
| 			} else { | ||||
| 				const selection = this.editor.model.document.selection; | ||||
| @@ -45,7 +40,7 @@ export default class MathCommand extends Command { | ||||
| 					display ? 'mathtex-display' : 'mathtex-inline', | ||||
| 					{ | ||||
| 						// Inherit all attributes from selection (e.g. color, background color, size). | ||||
| 						...Object.fromEntries(selection.getAttributes()), | ||||
| 						...Object.fromEntries( selection.getAttributes() ), | ||||
| 						equation, | ||||
| 						type: outputType, | ||||
| 						display, | ||||
|   | ||||
| @@ -27,8 +27,8 @@ | ||||
|     "@ckeditor/ckeditor5-dev-build-tools": "43.1.0", | ||||
|     "@ckeditor/ckeditor5-inspector": ">=4.1.0", | ||||
|     "@ckeditor/ckeditor5-package-tools": "4.1.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "~8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "@vitest/browser": "3.2.4", | ||||
|     "@vitest/coverage-istanbul": "3.2.4", | ||||
|     "ckeditor5": "47.0.0", | ||||
|   | ||||
| @@ -49,9 +49,4 @@ export interface HiddenSubtreeItem { | ||||
|      * the user moves it around. | ||||
|      */ | ||||
|     enforceBranches?: boolean; | ||||
|     /** | ||||
|      * If set to true, then the attributes of this note will be checked. Any owned attribute that does not match the | ||||
|      * definitions will be removed. | ||||
|      */ | ||||
|     enforceAttributes?: boolean; | ||||
| } | ||||
|   | ||||
| @@ -135,8 +135,6 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi | ||||
|     // Share settings | ||||
|     redirectBareDomain: boolean; | ||||
|     showLoginInShareTheme: boolean; | ||||
|     shareSubtree: boolean; | ||||
|     sharePath: string; | ||||
|  | ||||
|     // AI/LLM integration options | ||||
|     aiEnabled: boolean; | ||||
|   | ||||
| @@ -1,22 +1,98 @@ | ||||
| // Default list of allowed HTML tags | ||||
| export const SANITIZER_DEFAULT_ALLOWED_TAGS = [ | ||||
|     "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "p", "a", "ul", "ol", "li", "b", "i", "strong", "em", | ||||
|     "strike", "s", "del", "abbr", "code", "hr", "br", "div", "table", "thead", "caption", "tbody", "tfoot", | ||||
|     "tr", "th", "td", "pre", "section", "img", "figure", "figcaption", "span", "label", "input", "details", | ||||
|     "summary", "address", "aside", "footer", "header", "hgroup", "main", "nav", "dl", "dt", "menu", "bdi", | ||||
|     "bdo", "dfn", "kbd", "mark", "q", "time", "var", "wbr", "area", "map", "track", "video", "audio", "picture", | ||||
|     "del", "ins", | ||||
|     // for ENEX import | ||||
|     "en-media", | ||||
|     "h1", | ||||
|     "h2", | ||||
|     "h3", | ||||
|     "h4", | ||||
|     "h5", | ||||
|     "h6", | ||||
|     "blockquote", | ||||
|     "p", | ||||
|     "a", | ||||
|     "ul", | ||||
|     "ol", | ||||
|     "li", | ||||
|     "b", | ||||
|     "i", | ||||
|     "strong", | ||||
|     "em", | ||||
|     "strike", | ||||
|     "s", | ||||
|     "del", | ||||
|     "abbr", | ||||
|     "code", | ||||
|     "hr", | ||||
|     "br", | ||||
|     "div", | ||||
|     "table", | ||||
|     "thead", | ||||
|     "caption", | ||||
|     "tbody", | ||||
|     "tfoot", | ||||
|     "tr", | ||||
|     "th", | ||||
|     "td", | ||||
|     "pre", | ||||
|     "section", | ||||
|     "img", | ||||
|     "figure", | ||||
|     "figcaption", | ||||
|     "span", | ||||
|     "label", | ||||
|     "input", | ||||
|     "details", | ||||
|     "summary", | ||||
|     "address", | ||||
|     "aside", | ||||
|     "footer", | ||||
|     "header", | ||||
|     "hgroup", | ||||
|     "main", | ||||
|     "nav", | ||||
|     "dl", | ||||
|     "dt", | ||||
|     "menu", | ||||
|     "bdi", | ||||
|     "bdo", | ||||
|     "dfn", | ||||
|     "kbd", | ||||
|     "mark", | ||||
|     "q", | ||||
|     "time", | ||||
|     "var", | ||||
|     "wbr", | ||||
|     "area", | ||||
|     "map", | ||||
|     "track", | ||||
|     "video", | ||||
|     "audio", | ||||
|     "picture", | ||||
|     "del", | ||||
|     "ins", | ||||
|     "en-media", // for ENEX import | ||||
|     // Additional tags (https://github.com/TriliumNext/Trilium/issues/567) | ||||
|     "acronym", "article", "big", "button", "cite", "col", "colgroup", "data", "dd", "fieldset", "form", "legend", | ||||
|     "meter", "noscript", "option", "progress", "rp", "samp", "small", "sub", "sup", "template", "textarea", "tt" | ||||
|     "acronym", | ||||
|     "article", | ||||
|     "big", | ||||
|     "button", | ||||
|     "cite", | ||||
|     "col", | ||||
|     "colgroup", | ||||
|     "data", | ||||
|     "dd", | ||||
|     "fieldset", | ||||
|     "form", | ||||
|     "legend", | ||||
|     "meter", | ||||
|     "noscript", | ||||
|     "option", | ||||
|     "progress", | ||||
|     "rp", | ||||
|     "samp", | ||||
|     "small", | ||||
|     "sub", | ||||
|     "sup", | ||||
|     "template", | ||||
|     "textarea", | ||||
|     "tt" | ||||
| ] as const; | ||||
|  | ||||
| export const ALLOWED_PROTOCOLS = [ | ||||
|     'http', 'https', 'ftp', 'ftps', 'mailto', 'data', 'evernote', 'file', 'facetime', 'gemini', 'git', | ||||
|     'gopher', 'imap', 'irc', 'irc6', 'jabber', 'jar', 'lastfm', 'ldap', 'ldaps', 'magnet', 'message', | ||||
|     'mumble', 'nfs', 'onenote', 'pop', 'rmi', 's3', 'sftp', 'skype', 'sms', 'spotify', 'steam', 'svn', 'udp', | ||||
|     'view-source', 'vlc', 'vnc', 'ws', 'wss', 'xmpp', 'jdbc', 'slack', 'tel', 'smb', 'zotero', 'geo', | ||||
|     'mid', 'obsidian' | ||||
| ]; | ||||
|   | ||||
| @@ -24,8 +24,8 @@ | ||||
|   "devDependencies": { | ||||
|     "@digitak/esrun": "3.2.26", | ||||
|     "@types/swagger-ui": "5.21.1", | ||||
|     "@typescript-eslint/eslint-plugin": "8.46.0", | ||||
|     "@typescript-eslint/parser": "8.46.0", | ||||
|     "@typescript-eslint/eslint-plugin": "8.45.0", | ||||
|     "@typescript-eslint/parser": "8.45.0", | ||||
|     "dotenv": "17.2.3", | ||||
|     "esbuild": "0.25.10", | ||||
|     "eslint": "9.37.0", | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <link rel="shortcut icon" href="<%= relativePath %>favicon.ico"> | ||||
|     <link rel="shortcut icon" href="../favicon.ico"> | ||||
|     <title><%= t("share_404.title") %></title> | ||||
| </head> | ||||
| <body> | ||||
|   | ||||
| @@ -81,7 +81,7 @@ | ||||
| </head> | ||||
| <% | ||||
| const customLogoId = subRoot.note.getRelation("shareLogo")?.value; | ||||
| const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `${relativePath}${assetUrlFragment}/images/icon-color.svg`; | ||||
| const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `../${assetUrlFragment}/images/icon-color.svg`; | ||||
| const logoWidth = subRoot.note.getLabelValue("shareLogoWidth") ?? 53; | ||||
| const logoHeight = subRoot.note.getLabelValue("shareLogoHeight") ?? 40; | ||||
| const mobileLogoHeight = logoHeight && logoWidth ? 32 / (logoWidth / logoHeight) : ""; | ||||
|   | ||||
							
								
								
									
										260
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										260
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -8,7 +8,7 @@ overrides: | ||||
|   mermaid: 11.12.0 | ||||
|   preact: 10.27.2 | ||||
|   roughjs: 4.6.6 | ||||
|   '@types/express-serve-static-core': 5.1.0 | ||||
|   '@types/express-serve-static-core': 5.0.7 | ||||
|   flat@<5.0.1: '>=5.0.1' | ||||
|   debug@>=3.2.0 <3.2.7: '>=3.2.7' | ||||
|   nanoid@<3.3.8: '>=3.3.8' | ||||
| @@ -41,8 +41,8 @@ importers: | ||||
|         specifier: 4.0.1 | ||||
|         version: 4.0.1 | ||||
|       '@playwright/test': | ||||
|         specifier: 1.56.0 | ||||
|         version: 1.56.0 | ||||
|         specifier: 1.55.1 | ||||
|         version: 1.55.1 | ||||
|       '@triliumnext/server': | ||||
|         specifier: workspace:* | ||||
|         version: link:apps/server | ||||
| @@ -107,8 +107,8 @@ importers: | ||||
|         specifier: ~5.9.0 | ||||
|         version: 5.9.3 | ||||
|       typescript-eslint: | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       upath: | ||||
|         specifier: 2.0.1 | ||||
|         version: 2.0.1 | ||||
| @@ -694,8 +694,8 @@ importers: | ||||
|         specifier: 0.6.0 | ||||
|         version: 0.6.0 | ||||
|       openai: | ||||
|         specifier: 6.2.0 | ||||
|         version: 6.2.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4) | ||||
|         specifier: 6.1.0 | ||||
|         version: 6.1.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4) | ||||
|       rand-token: | ||||
|         specifier: 1.0.1 | ||||
|         version: 1.0.1 | ||||
| @@ -837,14 +837,14 @@ importers: | ||||
|         specifier: 4.1.0 | ||||
|         version: 4.1.0(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.18.8)(bufferutil@4.0.9)(esbuild@0.25.10)(utf-8-validate@6.0.5) | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: ~8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: ~8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@vitest/browser': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/coverage-istanbul': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(vitest@3.2.4) | ||||
| @@ -897,14 +897,14 @@ importers: | ||||
|         specifier: 4.1.0 | ||||
|         version: 4.1.0(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.18.8)(bufferutil@4.0.9)(esbuild@0.25.10)(utf-8-validate@6.0.5) | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: ~8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: ~8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@vitest/browser': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/coverage-istanbul': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(vitest@3.2.4) | ||||
| @@ -957,14 +957,14 @@ importers: | ||||
|         specifier: 4.1.0 | ||||
|         version: 4.1.0(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.18.8)(bufferutil@4.0.9)(esbuild@0.25.10)(utf-8-validate@6.0.5) | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: ~8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: ~8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@vitest/browser': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/coverage-istanbul': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(vitest@3.2.4) | ||||
| @@ -1024,14 +1024,14 @@ importers: | ||||
|         specifier: 4.1.0 | ||||
|         version: 4.1.0(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.18.8)(bufferutil@4.0.9)(esbuild@0.25.10)(utf-8-validate@6.0.5) | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: ~8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: ~8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@vitest/browser': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/coverage-istanbul': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(vitest@3.2.4) | ||||
| @@ -1091,14 +1091,14 @@ importers: | ||||
|         specifier: 4.1.0 | ||||
|         version: 4.1.0(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.18.8)(bufferutil@4.0.9)(esbuild@0.25.10)(utf-8-validate@6.0.5) | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: ~8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: ~8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@vitest/browser': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|         version: 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/coverage-istanbul': | ||||
|         specifier: 3.2.4 | ||||
|         version: 3.2.4(vitest@3.2.4) | ||||
| @@ -1315,11 +1315,11 @@ importers: | ||||
|         specifier: 5.21.1 | ||||
|         version: 5.21.1 | ||||
|       '@typescript-eslint/eslint-plugin': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': | ||||
|         specifier: 8.46.0 | ||||
|         version: 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|         specifier: 8.45.0 | ||||
|         version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       dotenv: | ||||
|         specifier: 17.2.3 | ||||
|         version: 17.2.3 | ||||
| @@ -3372,8 +3372,8 @@ packages: | ||||
|     resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} | ||||
|     engines: {node: '>=14'} | ||||
|  | ||||
|   '@playwright/test@1.56.0': | ||||
|     resolution: {integrity: sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==} | ||||
|   '@playwright/test@1.55.1': | ||||
|     resolution: {integrity: sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==} | ||||
|     engines: {node: '>=18'} | ||||
|     hasBin: true | ||||
|  | ||||
| @@ -4715,8 +4715,8 @@ packages: | ||||
|   '@types/express-http-proxy@1.6.7': | ||||
|     resolution: {integrity: sha512-CEp9pbnwVI1RzN9PXc+KESMxwUW5r1O7tkWb5h7Wg/YAIf+KulD/zKev8fbbn+Ljt0Yvs8MXwV2W6Id+cKxe2Q==} | ||||
|  | ||||
|   '@types/express-serve-static-core@5.1.0': | ||||
|     resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} | ||||
|   '@types/express-serve-static-core@5.0.7': | ||||
|     resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} | ||||
|  | ||||
|   '@types/express-session@1.18.2': | ||||
|     resolution: {integrity: sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==} | ||||
| @@ -4989,11 +4989,11 @@ packages: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/eslint-plugin@8.46.0': | ||||
|     resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} | ||||
|   '@typescript-eslint/eslint-plugin@8.45.0': | ||||
|     resolution: {integrity: sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       '@typescript-eslint/parser': ^8.46.0 | ||||
|       '@typescript-eslint/parser': ^8.45.0 | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
| @@ -5004,8 +5004,8 @@ packages: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/parser@8.46.0': | ||||
|     resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} | ||||
|   '@typescript-eslint/parser@8.45.0': | ||||
|     resolution: {integrity: sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
| @@ -5023,8 +5023,8 @@ packages: | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/project-service@8.46.0': | ||||
|     resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} | ||||
|   '@typescript-eslint/project-service@8.45.0': | ||||
|     resolution: {integrity: sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
| @@ -5037,8 +5037,8 @@ packages: | ||||
|     resolution: {integrity: sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@typescript-eslint/scope-manager@8.46.0': | ||||
|     resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} | ||||
|   '@typescript-eslint/scope-manager@8.45.0': | ||||
|     resolution: {integrity: sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@typescript-eslint/tsconfig-utils@8.40.0': | ||||
| @@ -5059,12 +5059,6 @@ packages: | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/tsconfig-utils@8.46.0': | ||||
|     resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/type-utils@8.40.0': | ||||
|     resolution: {integrity: sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
| @@ -5072,8 +5066,8 @@ packages: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/type-utils@8.46.0': | ||||
|     resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} | ||||
|   '@typescript-eslint/type-utils@8.45.0': | ||||
|     resolution: {integrity: sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
| @@ -5091,10 +5085,6 @@ packages: | ||||
|     resolution: {integrity: sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@typescript-eslint/types@8.46.0': | ||||
|     resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@typescript-eslint/typescript-estree@8.40.0': | ||||
|     resolution: {integrity: sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
| @@ -5107,8 +5097,8 @@ packages: | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/typescript-estree@8.46.0': | ||||
|     resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} | ||||
|   '@typescript-eslint/typescript-estree@8.45.0': | ||||
|     resolution: {integrity: sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
| @@ -5127,8 +5117,8 @@ packages: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   '@typescript-eslint/utils@8.46.0': | ||||
|     resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} | ||||
|   '@typescript-eslint/utils@8.45.0': | ||||
|     resolution: {integrity: sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
| @@ -5142,8 +5132,8 @@ packages: | ||||
|     resolution: {integrity: sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@typescript-eslint/visitor-keys@8.46.0': | ||||
|     resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} | ||||
|   '@typescript-eslint/visitor-keys@8.45.0': | ||||
|     resolution: {integrity: sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|  | ||||
|   '@ungap/structured-clone@1.3.0': | ||||
| @@ -10106,8 +10096,8 @@ packages: | ||||
|     resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} | ||||
|     engines: {node: '>=18'} | ||||
|  | ||||
|   openai@6.2.0: | ||||
|     resolution: {integrity: sha512-qqjzHls7F5xkXNGy9P1Ei1rorI5LWupUUFWP66zPU8FlZbiITX8SFcHMKNZg/NATJ0LpIZcMUFxSwQmdeQPwSw==} | ||||
|   openai@6.1.0: | ||||
|     resolution: {integrity: sha512-5sqb1wK67HoVgGlsPwcH2bUbkg66nnoIYKoyV9zi5pZPqh7EWlmSrSDjAh4O5jaIg/0rIlcDKBtWvZBuacmGZg==} | ||||
|     hasBin: true | ||||
|     peerDependencies: | ||||
|       ws: ^8.18.0 | ||||
| @@ -10438,13 +10428,13 @@ packages: | ||||
|   pkg-types@2.1.0: | ||||
|     resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} | ||||
|  | ||||
|   playwright-core@1.56.0: | ||||
|     resolution: {integrity: sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==} | ||||
|   playwright-core@1.55.1: | ||||
|     resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==} | ||||
|     engines: {node: '>=18'} | ||||
|     hasBin: true | ||||
|  | ||||
|   playwright@1.56.0: | ||||
|     resolution: {integrity: sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==} | ||||
|   playwright@1.55.1: | ||||
|     resolution: {integrity: sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==} | ||||
|     engines: {node: '>=18'} | ||||
|     hasBin: true | ||||
|  | ||||
| @@ -13022,8 +13012,8 @@ packages: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
|       typescript: '>=4.8.4 <6.0.0' | ||||
|  | ||||
|   typescript-eslint@8.46.0: | ||||
|     resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==} | ||||
|   typescript-eslint@8.45.0: | ||||
|     resolution: {integrity: sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==} | ||||
|     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | ||||
|     peerDependencies: | ||||
|       eslint: ^8.57.0 || ^9.0.0 | ||||
| @@ -14724,8 +14714,6 @@ snapshots: | ||||
|       '@ckeditor/ckeditor5-utils': 47.0.0 | ||||
|       '@ckeditor/ckeditor5-watchdog': 47.0.0 | ||||
|       es-toolkit: 1.39.5 | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.9.3)': | ||||
|     dependencies: | ||||
| @@ -14917,8 +14905,6 @@ snapshots: | ||||
|       '@ckeditor/ckeditor5-utils': 47.0.0 | ||||
|       ckeditor5: 47.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) | ||||
|       es-toolkit: 1.39.5 | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@ckeditor/ckeditor5-editor-multi-root@47.0.0': | ||||
|     dependencies: | ||||
| @@ -14941,8 +14927,6 @@ snapshots: | ||||
|       '@ckeditor/ckeditor5-table': 47.0.0 | ||||
|       '@ckeditor/ckeditor5-utils': 47.0.0 | ||||
|       ckeditor5: 47.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@ckeditor/ckeditor5-emoji@47.0.0': | ||||
|     dependencies: | ||||
| @@ -15114,8 +15098,6 @@ snapshots: | ||||
|       '@ckeditor/ckeditor5-widget': 47.0.0 | ||||
|       ckeditor5: 47.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) | ||||
|       es-toolkit: 1.39.5 | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@ckeditor/ckeditor5-icons@47.0.0': {} | ||||
|  | ||||
| @@ -15502,6 +15484,8 @@ snapshots: | ||||
|       '@ckeditor/ckeditor5-ui': 47.0.0 | ||||
|       '@ckeditor/ckeditor5-utils': 47.0.0 | ||||
|       ckeditor5: 47.0.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@ckeditor/ckeditor5-special-characters@47.0.0': | ||||
|     dependencies: | ||||
| @@ -17567,9 +17551,9 @@ snapshots: | ||||
|   '@pkgjs/parseargs@0.11.0': | ||||
|     optional: true | ||||
|  | ||||
|   '@playwright/test@1.56.0': | ||||
|   '@playwright/test@1.55.1': | ||||
|     dependencies: | ||||
|       playwright: 1.56.0 | ||||
|       playwright: 1.55.1 | ||||
|  | ||||
|   '@polka/url@1.0.0-next.29': {} | ||||
|  | ||||
| @@ -18793,7 +18777,7 @@ snapshots: | ||||
|  | ||||
|   '@types/connect-history-api-fallback@1.5.4': | ||||
|     dependencies: | ||||
|       '@types/express-serve-static-core': 5.1.0 | ||||
|       '@types/express-serve-static-core': 5.0.7 | ||||
|       '@types/node': 22.18.8 | ||||
|  | ||||
|   '@types/connect@3.4.38': | ||||
| @@ -18964,7 +18948,7 @@ snapshots: | ||||
|     dependencies: | ||||
|       '@types/express': 5.0.3 | ||||
|  | ||||
|   '@types/express-serve-static-core@5.1.0': | ||||
|   '@types/express-serve-static-core@5.0.7': | ||||
|     dependencies: | ||||
|       '@types/node': 22.18.8 | ||||
|       '@types/qs': 6.14.0 | ||||
| @@ -18978,14 +18962,14 @@ snapshots: | ||||
|   '@types/express@4.17.23': | ||||
|     dependencies: | ||||
|       '@types/body-parser': 1.19.6 | ||||
|       '@types/express-serve-static-core': 5.1.0 | ||||
|       '@types/express-serve-static-core': 5.0.7 | ||||
|       '@types/qs': 6.14.0 | ||||
|       '@types/serve-static': 1.15.9 | ||||
|  | ||||
|   '@types/express@5.0.3': | ||||
|     dependencies: | ||||
|       '@types/body-parser': 1.19.6 | ||||
|       '@types/express-serve-static-core': 5.1.0 | ||||
|       '@types/express-serve-static-core': 5.0.7 | ||||
|       '@types/serve-static': 1.15.9 | ||||
|  | ||||
|   '@types/fs-extra@11.0.4': | ||||
| @@ -19286,14 +19270,14 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|   '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@eslint-community/regexpp': 4.12.1 | ||||
|       '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/scope-manager': 8.46.0 | ||||
|       '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/visitor-keys': 8.46.0 | ||||
|       '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/scope-manager': 8.45.0 | ||||
|       '@typescript-eslint/type-utils': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/visitor-keys': 8.45.0 | ||||
|       eslint: 9.37.0(jiti@2.6.1) | ||||
|       graphemer: 1.4.0 | ||||
|       ignore: 7.0.5 | ||||
| @@ -19315,12 +19299,12 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|   '@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/scope-manager': 8.46.0 | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/visitor-keys': 8.46.0 | ||||
|       '@typescript-eslint/scope-manager': 8.45.0 | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/visitor-keys': 8.45.0 | ||||
|       debug: 4.4.3(supports-color@6.0.0) | ||||
|       eslint: 9.37.0(jiti@2.6.1) | ||||
|       typescript: 5.9.3 | ||||
| @@ -19345,10 +19329,10 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/project-service@8.46.0(typescript@5.9.3)': | ||||
|   '@typescript-eslint/project-service@8.45.0(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       debug: 4.4.3(supports-color@6.0.0) | ||||
|       typescript: 5.9.3 | ||||
|     transitivePeerDependencies: | ||||
| @@ -19364,10 +19348,10 @@ snapshots: | ||||
|       '@typescript-eslint/types': 8.44.1 | ||||
|       '@typescript-eslint/visitor-keys': 8.44.1 | ||||
|  | ||||
|   '@typescript-eslint/scope-manager@8.46.0': | ||||
|   '@typescript-eslint/scope-manager@8.45.0': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/visitor-keys': 8.46.0 | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       '@typescript-eslint/visitor-keys': 8.45.0 | ||||
|  | ||||
|   '@typescript-eslint/tsconfig-utils@8.40.0(typescript@5.9.3)': | ||||
|     dependencies: | ||||
| @@ -19381,10 +19365,6 @@ snapshots: | ||||
|     dependencies: | ||||
|       typescript: 5.9.3 | ||||
|  | ||||
|   '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       typescript: 5.9.3 | ||||
|  | ||||
|   '@typescript-eslint/type-utils@8.40.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/types': 8.40.0 | ||||
| @@ -19397,11 +19377,11 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/type-utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|   '@typescript-eslint/type-utils@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       debug: 4.4.3(supports-color@6.0.0) | ||||
|       eslint: 9.37.0(jiti@2.6.1) | ||||
|       ts-api-utils: 2.1.0(typescript@5.9.3) | ||||
| @@ -19415,8 +19395,6 @@ snapshots: | ||||
|  | ||||
|   '@typescript-eslint/types@8.45.0': {} | ||||
|  | ||||
|   '@typescript-eslint/types@8.46.0': {} | ||||
|  | ||||
|   '@typescript-eslint/typescript-estree@8.40.0(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/project-service': 8.40.0(typescript@5.9.3) | ||||
| @@ -19449,12 +19427,12 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)': | ||||
|   '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/visitor-keys': 8.46.0 | ||||
|       '@typescript-eslint/project-service': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       '@typescript-eslint/visitor-keys': 8.45.0 | ||||
|       debug: 4.4.3(supports-color@6.0.0) | ||||
|       fast-glob: 3.3.3 | ||||
|       is-glob: 4.0.3 | ||||
| @@ -19487,12 +19465,12 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   '@typescript-eslint/utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|   '@typescript-eslint/utils@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)': | ||||
|     dependencies: | ||||
|       '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1)) | ||||
|       '@typescript-eslint/scope-manager': 8.46.0 | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/scope-manager': 8.45.0 | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) | ||||
|       eslint: 9.37.0(jiti@2.6.1) | ||||
|       typescript: 5.9.3 | ||||
|     transitivePeerDependencies: | ||||
| @@ -19508,9 +19486,9 @@ snapshots: | ||||
|       '@typescript-eslint/types': 8.44.1 | ||||
|       eslint-visitor-keys: 4.2.1 | ||||
|  | ||||
|   '@typescript-eslint/visitor-keys@8.46.0': | ||||
|   '@typescript-eslint/visitor-keys@8.45.0': | ||||
|     dependencies: | ||||
|       '@typescript-eslint/types': 8.46.0 | ||||
|       '@typescript-eslint/types': 8.45.0 | ||||
|       eslint-visitor-keys: 4.2.1 | ||||
|  | ||||
|   '@ungap/structured-clone@1.3.0': {} | ||||
| @@ -19546,7 +19524,7 @@ snapshots: | ||||
|       - bufferutil | ||||
|       - utf-8-validate | ||||
|  | ||||
|   '@vitest/browser@3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))': | ||||
|   '@vitest/browser@3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))': | ||||
|     dependencies: | ||||
|       '@testing-library/dom': 10.4.0 | ||||
|       '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) | ||||
| @@ -19558,7 +19536,7 @@ snapshots: | ||||
|       vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@19.0.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) | ||||
|       ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) | ||||
|     optionalDependencies: | ||||
|       playwright: 1.56.0 | ||||
|       playwright: 1.55.1 | ||||
|       webdriverio: 9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) | ||||
|     transitivePeerDependencies: | ||||
|       - bufferutil | ||||
| @@ -19599,7 +19577,7 @@ snapshots: | ||||
|       tinyrainbow: 2.0.0 | ||||
|       vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(@vitest/browser@3.2.4)(@vitest/ui@3.2.4)(happy-dom@19.0.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) | ||||
|     optionalDependencies: | ||||
|       '@vitest/browser': 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/browser': 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
| @@ -25939,7 +25917,7 @@ snapshots: | ||||
|       is-inside-container: 1.0.0 | ||||
|       wsl-utils: 0.1.0 | ||||
|  | ||||
|   openai@6.2.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4): | ||||
|   openai@6.1.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4): | ||||
|     optionalDependencies: | ||||
|       ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) | ||||
|       zod: 3.24.4 | ||||
| @@ -26273,11 +26251,11 @@ snapshots: | ||||
|       exsolve: 1.0.5 | ||||
|       pathe: 2.0.3 | ||||
|  | ||||
|   playwright-core@1.56.0: {} | ||||
|   playwright-core@1.55.1: {} | ||||
|  | ||||
|   playwright@1.56.0: | ||||
|   playwright@1.55.1: | ||||
|     dependencies: | ||||
|       playwright-core: 1.56.0 | ||||
|       playwright-core: 1.55.1 | ||||
|     optionalDependencies: | ||||
|       fsevents: 2.3.2 | ||||
|  | ||||
| @@ -29456,12 +29434,12 @@ snapshots: | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   typescript-eslint@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3): | ||||
|   typescript-eslint@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3): | ||||
|     dependencies: | ||||
|       '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) | ||||
|       '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3) | ||||
|       eslint: 9.37.0(jiti@2.6.1) | ||||
|       typescript: 5.9.3 | ||||
|     transitivePeerDependencies: | ||||
| @@ -29828,7 +29806,7 @@ snapshots: | ||||
|     optionalDependencies: | ||||
|       '@types/debug': 4.1.12 | ||||
|       '@types/node': 22.18.8 | ||||
|       '@vitest/browser': 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.56.0)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/browser': 3.2.4(bufferutil@4.0.9)(msw@2.7.5(@types/node@22.18.8)(typescript@5.9.3))(playwright@1.55.1)(utf-8-validate@6.0.5)(vite@7.1.9(@types/node@22.18.8)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)(webdriverio@9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)) | ||||
|       '@vitest/ui': 3.2.4(vitest@3.2.4) | ||||
|       happy-dom: 19.0.2 | ||||
|       jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) | ||||
| @@ -29994,7 +29972,7 @@ snapshots: | ||||
|       '@types/bonjour': 3.5.13 | ||||
|       '@types/connect-history-api-fallback': 1.5.4 | ||||
|       '@types/express': 4.17.23 | ||||
|       '@types/express-serve-static-core': 5.1.0 | ||||
|       '@types/express-serve-static-core': 5.0.7 | ||||
|       '@types/serve-index': 1.9.4 | ||||
|       '@types/serve-static': 1.15.9 | ||||
|       '@types/sockjs': 0.3.36 | ||||
|   | ||||
| @@ -23,7 +23,7 @@ function copyNativeDependencies(projectRoot: string) { | ||||
|     cpSync(sourcePath, destPath, { recursive: true, dereference: true }); | ||||
| } | ||||
|  | ||||
| async function rebuildNativeDependencies(projectRoot: string) { | ||||
| function rebuildNativeDependencies(projectRoot: string) { | ||||
|     const electronVersion = determineElectronVersion(projectRoot); | ||||
|  | ||||
|     if (!electronVersion) { | ||||
| @@ -35,7 +35,7 @@ async function rebuildNativeDependencies(projectRoot: string) { | ||||
|     console.log(`Rebuilding ${projectRoot} with ${electronVersion} for ${targetArch}...`); | ||||
|  | ||||
|     const resolvedPath = resolve(projectRoot); | ||||
|     await rebuild({ | ||||
|     rebuild({ | ||||
|         projectRootPath: resolvedPath, | ||||
|         buildPath: resolvedPath, | ||||
|         electronVersion, | ||||
| @@ -64,5 +64,5 @@ function determineElectronVersion(projectRoot: string) { | ||||
|  | ||||
| for (const projectRoot of [ "apps/desktop", "apps/edit-docs" ]) { | ||||
|     copyNativeDependencies(projectRoot); | ||||
|     await rebuildNativeDependencies(projectRoot); | ||||
|     rebuildNativeDependencies(projectRoot); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user