mirror of
https://github.com/zadam/trilium.git
synced 2025-10-26 15:56:29 +01:00
Compare commits
80 Commits
kev/share-
...
feat/clean
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64f191b83b | ||
|
|
31c8e96d70 | ||
|
|
1191421388 | ||
|
|
831a184c2a | ||
|
|
c671f91bca | ||
|
|
fa436c7ce6 | ||
|
|
d1367286c9 | ||
|
|
d10b0fa823 | ||
|
|
545c8648b7 | ||
|
|
d6e9acc149 | ||
|
|
26e14aff7b | ||
|
|
280ec5b406 | ||
|
|
26081ffd36 | ||
|
|
f106cbf6c0 | ||
|
|
f3877a52ab | ||
|
|
5becf60a63 | ||
|
|
2ea96dc8f8 | ||
|
|
e48724662e | ||
|
|
745ce7de76 | ||
|
|
997217861c | ||
|
|
44f8e8b833 | ||
|
|
99e2b63ff0 | ||
|
|
0139d90ac7 | ||
|
|
5b7484c27c | ||
|
|
71e64be44c | ||
|
|
639651329a | ||
|
|
a7a0d3584a | ||
|
|
f765441f1e | ||
|
|
10cd5bf130 | ||
|
|
d93c5dfeea | ||
|
|
b58aac1298 | ||
|
|
d662718a4a | ||
|
|
bebd3d430b | ||
|
|
2fca995725 | ||
|
|
caa1ea12f1 | ||
|
|
f25e4ea391 | ||
|
|
05b433edb5 | ||
|
|
b8851565eb | ||
|
|
888d0d1084 | ||
|
|
0a25d4db0d | ||
|
|
d483b6e840 | ||
|
|
979fbe2e76 | ||
|
|
ea5564c6e6 | ||
|
|
6ab8750726 | ||
|
|
923eabd750 | ||
|
|
c52d6a6384 | ||
|
|
519b9648c6 | ||
|
|
b25fd6ca3a | ||
|
|
2bd8c215ff | ||
|
|
34e7901de9 | ||
|
|
30a191cedf | ||
|
|
128d8907c3 | ||
|
|
3b1d7d045e | ||
|
|
0ae9a29e0d | ||
|
|
f4b5ed73ad | ||
|
|
43166dbeb5 | ||
|
|
00b5aef890 | ||
|
|
1b7266f083 | ||
|
|
d1d4b47111 | ||
|
|
c90364bd76 | ||
|
|
6dc687ef43 | ||
|
|
0e31aab1ab | ||
|
|
b0030f89b7 | ||
|
|
9f0a0238cc | ||
|
|
dabdfaddec | ||
|
|
a8901e6dc8 | ||
|
|
ab901a5d32 | ||
|
|
56fc2d9b30 | ||
|
|
df45fa2e1e | ||
|
|
9a11fc13d7 | ||
|
|
d72a0d3c69 | ||
|
|
0be508ed70 | ||
|
|
37f3a9b19d | ||
|
|
81d2fbc057 | ||
|
|
1aecf66cbe | ||
|
|
fbe7d64e00 | ||
|
|
c9d151289c | ||
|
|
bba2f6db64 | ||
|
|
6725f81a00 | ||
|
|
8487c8cd03 |
@@ -35,7 +35,7 @@
|
||||
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.55.1",
|
||||
"@playwright/test": "1.56.0",
|
||||
"@stylistic/eslint-plugin": "5.4.0",
|
||||
"@types/express": "5.0.3",
|
||||
"@types/node": "22.18.8",
|
||||
|
||||
@@ -3,16 +3,7 @@ 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";
|
||||
|
||||
// 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'
|
||||
];
|
||||
import { ALLOWED_PROTOCOLS } from "@triliumnext/commons";
|
||||
|
||||
function getNotePathFromUrl(url: string) {
|
||||
const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url);
|
||||
|
||||
@@ -1743,9 +1743,17 @@
|
||||
"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_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": "共享整个子树,而不是仅共享笔记"
|
||||
},
|
||||
"time_selector": {
|
||||
"invalid_input": "输入的时间值不是有效数字。",
|
||||
|
||||
@@ -1907,9 +1907,17 @@
|
||||
"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_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"
|
||||
},
|
||||
"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 +1,6 @@
|
||||
{}
|
||||
{
|
||||
"about": {
|
||||
"title": "Acerca de \"Trillium Notes\"",
|
||||
"app_version": "Versão da aplicação:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ALLOWED_PROTOCOLS } from "../../../services/link.js";
|
||||
import { MIME_TYPE_AUTO } from "@triliumnext/commons";
|
||||
import { ALLOWED_PROTOCOLS, 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";
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
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,6 +90,10 @@ 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.98.1",
|
||||
"appVersion": "0.99.1",
|
||||
"files": [
|
||||
{
|
||||
"isClone": false,
|
||||
@@ -60,6 +60,13 @@
|
||||
"value": "dayGridMonth",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "dateTemplate",
|
||||
"value": "bRQvb9VCkc3t",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
}
|
||||
],
|
||||
"dataFileName": "Journal.dat",
|
||||
@@ -75,7 +82,7 @@
|
||||
"title": "Trilium Demo",
|
||||
"notePosition": 20,
|
||||
"prefix": null,
|
||||
"isExpanded": true,
|
||||
"isExpanded": false,
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
@@ -6033,6 +6040,68 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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,6 +637,12 @@
|
||||
</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>
|
||||
|
||||
24
apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html
vendored
Normal file
24
apps/edit-docs/demo/root/Miscellaneous/Day Note Template.html
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<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,10 +23,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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,6 +18,10 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# This script opens 4 terminal windows.
|
||||
|
||||
|
||||
@@ -26,18 +30,38 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
i="0"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
while [ $i -lt 4 ]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
do
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
xterm &
|
||||
|
||||
|
||||
@@ -46,10 +70,22 @@ 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.1.0",
|
||||
"openai": "6.2.0",
|
||||
"rand-token": "1.0.1",
|
||||
"safe-compare": "1.1.4",
|
||||
"sanitize-filename": "1.6.3",
|
||||
|
||||
Binary file not shown.
@@ -116,6 +116,13 @@ class="admonition tip">
|
||||
<td>JavaScript note which will be injected into the share page. JS note must
|
||||
be in the shared sub-tree as well. Consider using <code>share_hidden_from_tree</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>shareHtml</code>
|
||||
</td>
|
||||
<td>HTML note which will be injected into the share page at locations specified
|
||||
by the <code>shareHtmlLocation</code> label. HTML note must be in the shared
|
||||
sub-tree as well. Consider using <code>share_hidden_from_tree</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>shareTemplate</code>
|
||||
</td>
|
||||
|
||||
47
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Sharing.html
generated
vendored
47
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Sharing.html
generated
vendored
@@ -6,8 +6,7 @@ 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>
|
||||
@@ -189,11 +188,9 @@ class="image">
|
||||
<img src="Sharing_share-single-note.png" alt="Share Note">
|
||||
</p>
|
||||
</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>
|
||||
<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>
|
||||
</ol>
|
||||
<h2>Sharing a note subtree</h2>
|
||||
<p>When you share a note, you actually share the entire subtree of notes
|
||||
@@ -234,6 +231,34 @@ class="image">
|
||||
This allows you to access note attributes or traverse the note tree using
|
||||
the <code>fetchNote()</code> API, which retrieves note data based on its
|
||||
ID.</p>
|
||||
<h3>Adding custom HTML</h3>
|
||||
<p>You can inject custom HTML snippets into specific locations of the shared
|
||||
page using the <code>~shareHtml</code> relation. The HTML note should contain
|
||||
the raw HTML content you want to inject, and you can control where it appears
|
||||
by adding the <code>#shareHtmlLocation</code> label to the HTML snippet note
|
||||
itself.</p>
|
||||
<p>The <code>#shareHtmlLocation</code> label accepts values in the format <code>location:position</code>:</p>
|
||||
<ul>
|
||||
<li><strong>Locations</strong>: <code>head</code>, <code>body</code>, <code>content</code>
|
||||
</li>
|
||||
<li><strong>Positions</strong>: <code>start</code>, <code>end</code>
|
||||
</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<ul>
|
||||
<li><code>#shareHtmlLocation=head:start</code> - Injects HTML at the beginning
|
||||
of the <code><head></code> section</li>
|
||||
<li><code>#shareHtmlLocation=head:end</code> - Injects HTML at the end of the <code><head></code> section
|
||||
(default)</li>
|
||||
<li><code>#shareHtmlLocation=body:start</code> - Injects HTML at the beginning
|
||||
of the <code><body></code> section</li>
|
||||
<li><code>#shareHtmlLocation=content:start</code> - Injects HTML at the beginning
|
||||
of the content area</li>
|
||||
<li><code>#shareHtmlLocation=content:end</code> - Injects HTML at the end of
|
||||
the content area</li>
|
||||
</ul>
|
||||
<p>If no location is specified, the HTML will be injected at <code>content:end</code> by
|
||||
default.</p>
|
||||
<p>Example:</p><pre><code class="language-application-javascript-env-backend">const currentNote = await fetchNote();
|
||||
const parentNote = await fetchNote(currentNote.parentNoteIds[0]);
|
||||
|
||||
@@ -344,6 +369,14 @@ for (const attr of parentNote.attributes) {
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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 próxima nota no histórico",
|
||||
"forward-in-note-history": "Navegar para a nota seguinte 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 completa de notas",
|
||||
"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 de notas completa",
|
||||
"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 subnota da nota atual",
|
||||
"create-note-into-inbox": "Crie uma nota na caixa de entrada (se definida) ou na nota do dia",
|
||||
"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",
|
||||
"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": "Pular da árvore para os pormenores da nota e editar o título",
|
||||
"edit-note-title": "Saltar 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á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",
|
||||
"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",
|
||||
"open-new-window": "Abre nova janela vazia",
|
||||
"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",
|
||||
"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",
|
||||
"dialogs": "Diálogos",
|
||||
"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",
|
||||
"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",
|
||||
"text-note-operations": "Operações de nota de texto",
|
||||
"add-link-to-text": "Abrir diálogo e adicionar ligação ao texto",
|
||||
"add-link-to-text": "Abrir diálogo para 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,7 +16,8 @@ vi.mock("../../services/ws.js", () => ({
|
||||
default: {
|
||||
sendMessageToAllClients: vi.fn(),
|
||||
sendTransactionEntityChangesToAllClients: vi.fn(),
|
||||
setLastSyncedPush: vi.fn()
|
||||
setLastSyncedPush: vi.fn(),
|
||||
syncFailed() {}
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -81,7 +82,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;
|
||||
@@ -91,14 +92,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");
|
||||
}
|
||||
|
||||
@@ -154,7 +155,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),
|
||||
@@ -171,18 +172,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({
|
||||
@@ -202,7 +203,7 @@ describe("LLM API Tests", () => {
|
||||
title: "Test Update Chat"
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
|
||||
createdChatId = createResponse.body.id;
|
||||
}
|
||||
|
||||
@@ -224,7 +225,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);
|
||||
});
|
||||
});
|
||||
@@ -240,7 +241,7 @@ describe("LLM API Tests", () => {
|
||||
title: "Message Test Chat"
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
|
||||
testChatId = createResponse.body.id;
|
||||
});
|
||||
|
||||
@@ -260,10 +261,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({
|
||||
@@ -310,10 +311,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({});
|
||||
@@ -321,7 +322,7 @@ describe("LLM API Tests", () => {
|
||||
model: 'test-model',
|
||||
provider: 'test-provider'
|
||||
});
|
||||
|
||||
|
||||
// Create a fresh chat for each test
|
||||
const mockChat = {
|
||||
id: 'streaming-test-chat',
|
||||
@@ -331,15 +332,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;
|
||||
});
|
||||
|
||||
@@ -358,7 +359,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,
|
||||
@@ -372,17 +373,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',
|
||||
@@ -390,7 +391,7 @@ describe("LLM API Tests", () => {
|
||||
content: 'Hello',
|
||||
done: false
|
||||
});
|
||||
|
||||
|
||||
expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({
|
||||
type: 'llm-stream',
|
||||
chatNoteId: testChatId,
|
||||
@@ -402,7 +403,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,
|
||||
@@ -419,7 +420,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,
|
||||
@@ -436,7 +437,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,
|
||||
@@ -467,7 +468,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, {});
|
||||
@@ -475,7 +476,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,
|
||||
@@ -493,10 +494,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',
|
||||
@@ -517,7 +518,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,
|
||||
@@ -525,10 +526,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',
|
||||
@@ -536,7 +537,7 @@ describe("LLM API Tests", () => {
|
||||
thinking: 'Analyzing the question...',
|
||||
done: false
|
||||
});
|
||||
|
||||
|
||||
expect(ws.sendMessageToAllClients).toHaveBeenCalledWith({
|
||||
type: 'llm-stream',
|
||||
chatNoteId: testChatId,
|
||||
@@ -564,7 +565,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,
|
||||
@@ -572,10 +573,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',
|
||||
@@ -597,7 +598,7 @@ describe("LLM API Tests", () => {
|
||||
|
||||
const response = await supertest(app)
|
||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||
|
||||
|
||||
.send({
|
||||
content: "This will fail",
|
||||
useAdvancedContext: false,
|
||||
@@ -605,10 +606,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',
|
||||
@@ -625,7 +626,7 @@ describe("LLM API Tests", () => {
|
||||
|
||||
const response = await supertest(app)
|
||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||
|
||||
|
||||
.send({
|
||||
content: "Hello AI",
|
||||
useAdvancedContext: false,
|
||||
@@ -633,10 +634,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',
|
||||
@@ -655,7 +656,7 @@ describe("LLM API Tests", () => {
|
||||
|
||||
await supertest(app)
|
||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||
|
||||
|
||||
.send({
|
||||
content: "Save this response",
|
||||
useAdvancedContext: false,
|
||||
@@ -680,10 +681,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,
|
||||
@@ -692,7 +693,7 @@ describe("LLM API Tests", () => {
|
||||
);
|
||||
|
||||
const responses = await Promise.all(promises);
|
||||
|
||||
|
||||
// All should succeed
|
||||
responses.forEach(response => {
|
||||
expect(response.status).toBe(200);
|
||||
@@ -716,7 +717,7 @@ describe("LLM API Tests", () => {
|
||||
|
||||
const response = await supertest(app)
|
||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||
|
||||
|
||||
.send({
|
||||
content: "Generate large response",
|
||||
useAdvancedContext: false,
|
||||
@@ -724,10 +725,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
|
||||
@@ -741,7 +742,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);
|
||||
@@ -750,7 +751,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
|
||||
});
|
||||
@@ -762,7 +763,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
|
||||
@@ -786,4 +787,4 @@ describe("LLM API Tests", () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -97,6 +97,8 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
|
||||
"allowedHtmlTags",
|
||||
"redirectBareDomain",
|
||||
"showLoginInShareTheme",
|
||||
"shareSubtree",
|
||||
"sharePath",
|
||||
"splitEditorOrientation",
|
||||
"seenCallToActions",
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ 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,9 +37,26 @@ 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) {
|
||||
@@ -81,15 +98,6 @@ 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");
|
||||
|
||||
@@ -66,6 +66,7 @@ export default [
|
||||
{ type: "label", name: "shareDisallowRobotIndexing" },
|
||||
{ type: "label", name: "shareCredentials" },
|
||||
{ type: "label", name: "shareIndex" },
|
||||
{ type: "label", name: "shareHtmlLocation" },
|
||||
{ type: "label", name: "displayRelations" },
|
||||
{ type: "label", name: "hideRelations" },
|
||||
{ type: "label", name: "titleTemplate", isDangerous: true },
|
||||
@@ -105,6 +106,7 @@ export default [
|
||||
{ type: "relation", name: "renderNote", isDangerous: true },
|
||||
{ type: "relation", name: "shareCss" },
|
||||
{ type: "relation", name: "shareJs" },
|
||||
{ type: "relation", name: "shareHtml" },
|
||||
{ type: "relation", name: "shareTemplate" },
|
||||
{ type: "relation", name: "shareFavicon" }
|
||||
];
|
||||
|
||||
@@ -9,13 +9,13 @@ import { changeLanguage } from "./i18n.js";
|
||||
import { deferred } from "./utils.js";
|
||||
|
||||
describe("Hidden Subtree", () => {
|
||||
describe("Launcher movement persistence", () => {
|
||||
beforeAll(async () => {
|
||||
sql_init.initializeDb();
|
||||
await sql_init.dbReady;
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
});
|
||||
beforeAll(async () => {
|
||||
sql_init.initializeDb();
|
||||
await sql_init.dbReady;
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
});
|
||||
|
||||
describe("Launcher movement persistence", () => {
|
||||
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,4 +119,14 @@ 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,6 +441,15 @@ 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,17 +1,7 @@
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
import { sanitizeUrl } from "@braintree/sanitize-url";
|
||||
import optionService from "./options.js";
|
||||
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'
|
||||
];
|
||||
import { ALLOWED_PROTOCOLS, SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons";
|
||||
|
||||
// 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, afterEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { StreamProcessor, createStreamHandler, processProviderStream, extractStreamStats, performProviderHealthCheck } from './stream_handler.js';
|
||||
import type { StreamProcessingOptions, StreamChunk, ProviderStreamOptions } from './stream_handler.js';
|
||||
import type { StreamProcessingOptions, StreamChunk } 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,8 +196,10 @@ 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);
|
||||
renderText(result, note, relativePath);
|
||||
} 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="../${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 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>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.getElementById('content'));
|
||||
|
||||
@@ -9,6 +9,7 @@ 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) => {
|
||||
@@ -43,3 +44,39 @@ 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 } from "express";
|
||||
import type { Request, Response, Router, NextFunction } from "express";
|
||||
|
||||
import shaca from "./shaca/shaca.js";
|
||||
import shacaLoader from "./shaca/shaca_loader.js";
|
||||
@@ -139,17 +139,21 @@ function renderImageAttachment(image: SNote, res: Response, attachmentName: stri
|
||||
}
|
||||
|
||||
function register(router: Router) {
|
||||
function renderNote(note: SNote, req: Request, res: Response) {
|
||||
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);
|
||||
|
||||
if (!note) {
|
||||
console.log("Unable to find note ", note);
|
||||
res.status(404);
|
||||
renderDefault(res, "404");
|
||||
renderDefault(res, "404", { relativePath, t });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkNoteAccess(note.noteId, req, res)) {
|
||||
requestCredentials(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,18 +165,20 @@ function register(router: Router) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { header, content, isEmpty } = contentRenderer.getContent(note);
|
||||
const { header, content, isEmpty } = contentRenderer.getContent(note, relativePath);
|
||||
const subRoot = getSharedSubTreeRoot(note);
|
||||
const showLoginInShareTheme = options.getOption("showLoginInShareTheme");
|
||||
|
||||
const opts = {
|
||||
note,
|
||||
header,
|
||||
content,
|
||||
isEmpty,
|
||||
subRoot,
|
||||
assetPath: isDev ? assetPath : `../${assetPath}`,
|
||||
assetPath: isDev ? assetPath : `${relativePath}${assetPath}`,
|
||||
assetUrlFragment,
|
||||
appPath: isDev ? appPath : `../${appPath}`,
|
||||
appPath: isDev ? appPath : `${relativePath}${appPath}`,
|
||||
relativePath,
|
||||
showLoginInShareTheme,
|
||||
t,
|
||||
isDev
|
||||
@@ -219,184 +225,165 @@ function register(router: Router) {
|
||||
}
|
||||
}
|
||||
|
||||
router.get("/share/", (req, res) => {
|
||||
if (req.path.substr(-1) !== "/") {
|
||||
res.redirect("../share/");
|
||||
return;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 });
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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; };
|
||||
@@ -9,6 +10,7 @@ interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
|
||||
id?: string | undefined;
|
||||
title?: string;
|
||||
content?: string;
|
||||
children?: NoteDefinition[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +53,18 @@ 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: "threads"
|
||||
pool: "vmForks"
|
||||
},
|
||||
}));
|
||||
|
||||
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
|
||||
|
||||
26563
docs/User Guide/!!!meta.json
vendored
26563
docs/User Guide/!!!meta.json
vendored
File diff suppressed because it is too large
Load Diff
@@ -50,5 +50,6 @@ These relations are supported and used internally by Trilium.
|
||||
| `widget_relation` | target of this relation will be executed and rendered as a widget in the sidebar |
|
||||
| `shareCss` | CSS note which will be injected into the share page. CSS note must be in the shared sub-tree as well. Consider using `share_hidden_from_tree` and `share_omit_default_css` as well. |
|
||||
| `shareJs` | JavaScript note which will be injected into the share page. JS note must be in the shared sub-tree as well. Consider using `share_hidden_from_tree`. |
|
||||
| `shareHtml` | HTML note which will be injected into the share page at locations specified by the `shareHtmlLocation` label. HTML note must be in the shared sub-tree as well. Consider using `share_hidden_from_tree`. |
|
||||
| `shareTemplate` | Embedded JavaScript note that will be used as the template for displaying the shared note. Falls back to the default template. Consider using `share_hidden_from_tree`. |
|
||||
| `shareFavicon` | Favicon note to be set in the shared page. Typically you want to set it to share root and make it inheritable. Favicon note must be in the shared sub-tree as well. Consider using `share_hidden_from_tree`. |
|
||||
@@ -67,6 +67,25 @@ The default design should be a good starting point, but you can customize it usi
|
||||
|
||||
You can inject custom JavaScript into the shared note using the `~shareJs` relation. This allows you to access note attributes or traverse the note tree using the `fetchNote()` API, which retrieves note data based on its ID.
|
||||
|
||||
### Adding custom HTML
|
||||
|
||||
You can inject custom HTML snippets into specific locations of the shared page using the `~shareHtml` relation. The HTML note should contain the raw HTML content you want to inject, and you can control where it appears by adding the `#shareHtmlLocation` label to the HTML snippet note itself.
|
||||
|
||||
The `#shareHtmlLocation` label accepts values in the format `location:position`:
|
||||
|
||||
* **Locations**: `head`, `body`, `content`
|
||||
* **Positions**: `start`, `end`
|
||||
|
||||
For example:
|
||||
|
||||
* `#shareHtmlLocation=head:start` - Injects HTML at the beginning of the `<head>` section
|
||||
* `#shareHtmlLocation=head:end` - Injects HTML at the end of the `<head>` section (default)
|
||||
* `#shareHtmlLocation=body:start` - Injects HTML at the beginning of the `<body>` section
|
||||
* `#shareHtmlLocation=content:start` - Injects HTML at the beginning of the content area
|
||||
* `#shareHtmlLocation=content:end` - Injects HTML at the end of the content area
|
||||
|
||||
If no location is specified, the HTML will be injected at `content:end` by default.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
@@ -104,9 +123,19 @@ 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></tbody></table>
|
||||
<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>
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -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 || true
|
||||
pnpm postinstall
|
||||
'';
|
||||
buildTask = "desktop:build";
|
||||
mainProgram = "trilium";
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@electron/rebuild": "4.0.1",
|
||||
"@playwright/test": "1.55.1",
|
||||
"@playwright/test": "1.56.0",
|
||||
"@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.45.0",
|
||||
"typescript-eslint": "8.46.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.0",
|
||||
"packageManager": "pnpm@10.18.1",
|
||||
"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.0.7",
|
||||
"@types/express-serve-static-core": "5.1.0",
|
||||
"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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "~8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "~8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "~8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "~8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.0",
|
||||
"@vitest/browser": "3.2.4",
|
||||
"@vitest/coverage-istanbul": "3.2.4",
|
||||
"ckeditor5": "47.0.0",
|
||||
|
||||
@@ -30,7 +30,12 @@ export default class MathCommand extends Command {
|
||||
|
||||
mathtex = writer.createElement(
|
||||
display ? 'mathtex-display' : 'mathtex-inline',
|
||||
{ equation, type, display }
|
||||
{
|
||||
...Object.fromEntries(selection.getAttributes()),
|
||||
equation,
|
||||
type,
|
||||
display
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const selection = this.editor.model.document.selection;
|
||||
@@ -40,7 +45,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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "~8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.0",
|
||||
"@vitest/browser": "3.2.4",
|
||||
"@vitest/coverage-istanbul": "3.2.4",
|
||||
"ckeditor5": "47.0.0",
|
||||
|
||||
@@ -49,4 +49,9 @@ 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,6 +135,8 @@ export interface OptionDefinitions extends KeyboardShortcutsOptions<KeyboardActi
|
||||
// Share settings
|
||||
redirectBareDomain: boolean;
|
||||
showLoginInShareTheme: boolean;
|
||||
shareSubtree: boolean;
|
||||
sharePath: string;
|
||||
|
||||
// AI/LLM integration options
|
||||
aiEnabled: boolean;
|
||||
|
||||
@@ -1,98 +1,22 @@
|
||||
// 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",
|
||||
"en-media", // for ENEX import
|
||||
"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",
|
||||
// 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.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.0",
|
||||
"@typescript-eslint/parser": "8.46.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="../favicon.ico">
|
||||
<link rel="shortcut icon" href="<%= relativePath %>favicon.ico">
|
||||
<title><%= t("share_404.title") %></title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,7 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<% const hasTree = subRoot.note.hasVisibleChildren(); %>
|
||||
<%
|
||||
const hasTree = subRoot.note.hasVisibleChildren();
|
||||
|
||||
// Collect HTML snippets by location
|
||||
const htmlSnippetsByLocation = {};
|
||||
for (const htmlRelation of note.getRelations("shareHtml")) {
|
||||
const htmlNote = htmlRelation.targetNote;
|
||||
if (htmlNote) {
|
||||
let location = htmlNote.getLabelValue("shareHtmlLocation") || "content:end";
|
||||
// Default to :end if no position specified
|
||||
if (!location.includes(":")) {
|
||||
location = location + ":end";
|
||||
}
|
||||
if (!htmlSnippetsByLocation[location]) {
|
||||
htmlSnippetsByLocation[location] = [];
|
||||
}
|
||||
htmlSnippetsByLocation[location].push(htmlNote.getContent());
|
||||
}
|
||||
}
|
||||
const renderSnippets = (location) => {
|
||||
const snippets = htmlSnippetsByLocation[location];
|
||||
return snippets ? snippets.join("\n") : "";
|
||||
};
|
||||
%>
|
||||
<%- renderSnippets("head:start") %>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
@@ -53,10 +77,11 @@
|
||||
<meta name="twitter:image" content="<%= openGraphImage %>">
|
||||
<!-- Meta Tags Generated via https://opengraph.dev -->
|
||||
<meta name="theme-color" content="<%= openGraphColor %>">
|
||||
<%- renderSnippets("head:end") %>
|
||||
</head>
|
||||
<%
|
||||
const customLogoId = subRoot.note.getRelation("shareLogo")?.value;
|
||||
const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `../${assetUrlFragment}/images/icon-color.svg`;
|
||||
const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `${relativePath}${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) : "";
|
||||
@@ -72,6 +97,7 @@ content = content.replaceAll(headingRe, (...match) => {
|
||||
});
|
||||
%>
|
||||
<body data-note-id="<%= note.noteId %>" class="type-<%= note.type %><%= themeClass %>" data-ancestor-note-id="<%= subRoot.note.noteId %>">
|
||||
<%- renderSnippets("body:start") %>
|
||||
<div id="mobile-header">
|
||||
<a href="<%= shareRootLink %>">
|
||||
<img src="<%= logoUrl %>" width="32" height="<%= mobileLogoHeight %>" alt="Logo" />
|
||||
@@ -121,8 +147,8 @@ content = content.replaceAll(headingRe, (...match) => {
|
||||
</div>
|
||||
<div id="right-pane">
|
||||
<div id="main">
|
||||
|
||||
<div id="content" class="type-<%= note.type %><% if (note.type === "text") { %> ck-content<% } %><% if (isEmpty) { %> no-content<% } %>">
|
||||
<%- renderSnippets("content:start") %>
|
||||
<h1 id="title"><%= note.title %></h1>
|
||||
<% if (isEmpty && (!note.hasVisibleChildren() && note.type !== "book")) { %>
|
||||
<p>This note has no content.</p>
|
||||
@@ -132,6 +158,7 @@ content = content.replaceAll(headingRe, (...match) => {
|
||||
%>
|
||||
<%- content %>
|
||||
<% } %>
|
||||
<%- renderSnippets("content:end") %>
|
||||
</div>
|
||||
|
||||
<% if (note.hasVisibleChildren() || note.type === "book") { %>
|
||||
@@ -164,7 +191,7 @@ content = content.replaceAll(headingRe, (...match) => {
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (hasTree) { %>
|
||||
<% if (hasTree) { %>
|
||||
<%- include("prev_next", { note: note, subRoot: subRoot }) %>
|
||||
<% } %>
|
||||
</footer>
|
||||
@@ -205,5 +232,6 @@ content = content.replaceAll(headingRe, (...match) => {
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<%- renderSnippets("body:end") %>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
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.0.7
|
||||
'@types/express-serve-static-core': 5.1.0
|
||||
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.55.1
|
||||
version: 1.55.1
|
||||
specifier: 1.56.0
|
||||
version: 1.56.0
|
||||
'@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.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.1.0
|
||||
version: 6.1.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4)
|
||||
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)
|
||||
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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.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))
|
||||
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))
|
||||
'@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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.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))
|
||||
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))
|
||||
'@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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.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))
|
||||
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))
|
||||
'@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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.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))
|
||||
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))
|
||||
'@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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.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))
|
||||
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))
|
||||
'@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.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)
|
||||
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)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: 8.45.0
|
||||
version: 8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
specifier: 8.46.0
|
||||
version: 8.46.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.55.1':
|
||||
resolution: {integrity: sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==}
|
||||
'@playwright/test@1.56.0':
|
||||
resolution: {integrity: sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==}
|
||||
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.0.7':
|
||||
resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==}
|
||||
'@types/express-serve-static-core@5.1.0':
|
||||
resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==}
|
||||
|
||||
'@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.45.0':
|
||||
resolution: {integrity: sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==}
|
||||
'@typescript-eslint/eslint-plugin@8.46.0':
|
||||
resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.45.0
|
||||
'@typescript-eslint/parser': ^8.46.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.45.0':
|
||||
resolution: {integrity: sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==}
|
||||
'@typescript-eslint/parser@8.46.0':
|
||||
resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==}
|
||||
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.45.0':
|
||||
resolution: {integrity: sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==}
|
||||
'@typescript-eslint/project-service@8.46.0':
|
||||
resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==}
|
||||
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.45.0':
|
||||
resolution: {integrity: sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==}
|
||||
'@typescript-eslint/scope-manager@8.46.0':
|
||||
resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.40.0':
|
||||
@@ -5059,6 +5059,12 @@ 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}
|
||||
@@ -5066,8 +5072,8 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.45.0':
|
||||
resolution: {integrity: sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==}
|
||||
'@typescript-eslint/type-utils@8.46.0':
|
||||
resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -5085,6 +5091,10 @@ 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}
|
||||
@@ -5097,8 +5107,8 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.45.0':
|
||||
resolution: {integrity: sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==}
|
||||
'@typescript-eslint/typescript-estree@8.46.0':
|
||||
resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
@@ -5117,8 +5127,8 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/utils@8.45.0':
|
||||
resolution: {integrity: sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==}
|
||||
'@typescript-eslint/utils@8.46.0':
|
||||
resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -5132,8 +5142,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.45.0':
|
||||
resolution: {integrity: sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==}
|
||||
'@typescript-eslint/visitor-keys@8.46.0':
|
||||
resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@ungap/structured-clone@1.3.0':
|
||||
@@ -10096,8 +10106,8 @@ packages:
|
||||
resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
openai@6.1.0:
|
||||
resolution: {integrity: sha512-5sqb1wK67HoVgGlsPwcH2bUbkg66nnoIYKoyV9zi5pZPqh7EWlmSrSDjAh4O5jaIg/0rIlcDKBtWvZBuacmGZg==}
|
||||
openai@6.2.0:
|
||||
resolution: {integrity: sha512-qqjzHls7F5xkXNGy9P1Ei1rorI5LWupUUFWP66zPU8FlZbiITX8SFcHMKNZg/NATJ0LpIZcMUFxSwQmdeQPwSw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
ws: ^8.18.0
|
||||
@@ -10428,13 +10438,13 @@ packages:
|
||||
pkg-types@2.1.0:
|
||||
resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==}
|
||||
|
||||
playwright-core@1.55.1:
|
||||
resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==}
|
||||
playwright-core@1.56.0:
|
||||
resolution: {integrity: sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
playwright@1.55.1:
|
||||
resolution: {integrity: sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==}
|
||||
playwright@1.56.0:
|
||||
resolution: {integrity: sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -13012,8 +13022,8 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
typescript-eslint@8.45.0:
|
||||
resolution: {integrity: sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==}
|
||||
typescript-eslint@8.46.0:
|
||||
resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
@@ -14714,6 +14724,8 @@ 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:
|
||||
@@ -14905,6 +14917,8 @@ 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:
|
||||
@@ -14927,6 +14941,8 @@ 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:
|
||||
@@ -15098,6 +15114,8 @@ 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': {}
|
||||
|
||||
@@ -15484,8 +15502,6 @@ 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:
|
||||
@@ -17551,9 +17567,9 @@ snapshots:
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@playwright/test@1.55.1':
|
||||
'@playwright/test@1.56.0':
|
||||
dependencies:
|
||||
playwright: 1.55.1
|
||||
playwright: 1.56.0
|
||||
|
||||
'@polka/url@1.0.0-next.29': {}
|
||||
|
||||
@@ -18777,7 +18793,7 @@ snapshots:
|
||||
|
||||
'@types/connect-history-api-fallback@1.5.4':
|
||||
dependencies:
|
||||
'@types/express-serve-static-core': 5.0.7
|
||||
'@types/express-serve-static-core': 5.1.0
|
||||
'@types/node': 22.18.8
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
@@ -18948,7 +18964,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/express': 5.0.3
|
||||
|
||||
'@types/express-serve-static-core@5.0.7':
|
||||
'@types/express-serve-static-core@5.1.0':
|
||||
dependencies:
|
||||
'@types/node': 22.18.8
|
||||
'@types/qs': 6.14.0
|
||||
@@ -18962,14 +18978,14 @@ snapshots:
|
||||
'@types/express@4.17.23':
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.6
|
||||
'@types/express-serve-static-core': 5.0.7
|
||||
'@types/express-serve-static-core': 5.1.0
|
||||
'@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.0.7
|
||||
'@types/express-serve-static-core': 5.1.0
|
||||
'@types/serve-static': 1.15.9
|
||||
|
||||
'@types/fs-extra@11.0.4':
|
||||
@@ -19270,14 +19286,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@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/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)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.1
|
||||
'@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
|
||||
'@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
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
graphemer: 1.4.0
|
||||
ignore: 7.0.5
|
||||
@@ -19299,12 +19315,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.45.0(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)':
|
||||
dependencies:
|
||||
'@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
|
||||
'@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
|
||||
debug: 4.4.3(supports-color@6.0.0)
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
@@ -19329,10 +19345,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.45.0(typescript@5.9.3)':
|
||||
'@typescript-eslint/project-service@8.46.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.45.0
|
||||
'@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.46.0
|
||||
debug: 4.4.3(supports-color@6.0.0)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
@@ -19348,10 +19364,10 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.44.1
|
||||
'@typescript-eslint/visitor-keys': 8.44.1
|
||||
|
||||
'@typescript-eslint/scope-manager@8.45.0':
|
||||
'@typescript-eslint/scope-manager@8.46.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.45.0
|
||||
'@typescript-eslint/visitor-keys': 8.45.0
|
||||
'@typescript-eslint/types': 8.46.0
|
||||
'@typescript-eslint/visitor-keys': 8.46.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.40.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
@@ -19365,6 +19381,10 @@ 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
|
||||
@@ -19377,11 +19397,11 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/type-utils@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
'@typescript-eslint/type-utils@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@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)
|
||||
'@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)
|
||||
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)
|
||||
@@ -19395,6 +19415,8 @@ 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)
|
||||
@@ -19427,12 +19449,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.3)':
|
||||
'@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@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
|
||||
'@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
|
||||
debug: 4.4.3(supports-color@6.0.0)
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
@@ -19465,12 +19487,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.45.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)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.6.1))
|
||||
'@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/scope-manager': 8.46.0
|
||||
'@typescript-eslint/types': 8.46.0
|
||||
'@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3)
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
@@ -19486,9 +19508,9 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.44.1
|
||||
eslint-visitor-keys: 4.2.1
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.45.0':
|
||||
'@typescript-eslint/visitor-keys@8.46.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.45.0
|
||||
'@typescript-eslint/types': 8.46.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
@@ -19524,7 +19546,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.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/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))':
|
||||
dependencies:
|
||||
'@testing-library/dom': 10.4.0
|
||||
'@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0)
|
||||
@@ -19536,7 +19558,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.55.1
|
||||
playwright: 1.56.0
|
||||
webdriverio: 9.20.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -19577,7 +19599,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.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/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))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -25917,7 +25939,7 @@ snapshots:
|
||||
is-inside-container: 1.0.0
|
||||
wsl-utils: 0.1.0
|
||||
|
||||
openai@6.1.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.24.4):
|
||||
openai@6.2.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
|
||||
@@ -26251,11 +26273,11 @@ snapshots:
|
||||
exsolve: 1.0.5
|
||||
pathe: 2.0.3
|
||||
|
||||
playwright-core@1.55.1: {}
|
||||
playwright-core@1.56.0: {}
|
||||
|
||||
playwright@1.55.1:
|
||||
playwright@1.56.0:
|
||||
dependencies:
|
||||
playwright-core: 1.55.1
|
||||
playwright-core: 1.56.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
@@ -29434,12 +29456,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
typescript-eslint@8.45.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
typescript-eslint@8.46.0(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@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)
|
||||
'@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)
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
@@ -29806,7 +29828,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.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/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/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)
|
||||
@@ -29972,7 +29994,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.0.7
|
||||
'@types/express-serve-static-core': 5.1.0
|
||||
'@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 });
|
||||
}
|
||||
|
||||
function rebuildNativeDependencies(projectRoot: string) {
|
||||
async function rebuildNativeDependencies(projectRoot: string) {
|
||||
const electronVersion = determineElectronVersion(projectRoot);
|
||||
|
||||
if (!electronVersion) {
|
||||
@@ -35,7 +35,7 @@ function rebuildNativeDependencies(projectRoot: string) {
|
||||
console.log(`Rebuilding ${projectRoot} with ${electronVersion} for ${targetArch}...`);
|
||||
|
||||
const resolvedPath = resolve(projectRoot);
|
||||
rebuild({
|
||||
await 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);
|
||||
rebuildNativeDependencies(projectRoot);
|
||||
await rebuildNativeDependencies(projectRoot);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user