This commit is contained in:
Elian Doran 2025-11-12 19:59:36 +02:00
commit 76f791da93
No known key found for this signature in database
47 changed files with 1160 additions and 463 deletions

View File

@ -4,6 +4,7 @@ on:
push:
branches:
- main
- hotfix
paths-ignore:
- "apps/website/**"
pull_request:
@ -13,8 +14,24 @@ permissions:
contents: read
jobs:
main:
runs-on: ubuntu-latest
e2e:
strategy:
fail-fast: false
matrix:
include:
- name: linux-x64
os: ubuntu-22.04
arch: x64
- name: linux-arm64
os: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.os }}
name: E2E tests on ${{ matrix.name }}
env:
TRILIUM_DOCKER: 1
TRILIUM_PORT: 8082
TRILIUM_DATA_DIR: "${{ github.workspace }}/apps/server/spec/db"
TRILIUM_INTEGRATION_TEST: memory
steps:
- uses: actions/checkout@v5
with:
@ -29,9 +46,34 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps
- run: pnpm --filter server-e2e e2e
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps
- name: Build the server
uses: ./.github/actions/build-server
with:
os: linux
arch: ${{ matrix.arch }}
- name: Unpack and start the server
run: |
version=$(node --eval "console.log(require('./package.json').version)")
file=$(find ./upload -name '*.tar.xz' -print -quit)
name=$(basename "$file" .tar.xz)
mkdir -p ./server-dist
tar -xvf "$file" -C ./server-dist
server_dir="./server-dist/TriliumNotes-Server-$version-linux-${{ matrix.arch }}"
if [ ! -d "$server_dir" ]; then
echo Missing dir.
exit 1
fi
cd "$server_dir"
"./trilium.sh" &
sleep 10
- name: Server end-to-end tests
run: pnpm --filter server-e2e e2e
- name: Upload test report
if: failure()
@ -39,3 +81,7 @@ jobs:
with:
name: e2e report
path: apps/server-e2e/test-output
- name: Kill the server
if: always()
run: pkill -f trilium || true

View File

@ -9,9 +9,9 @@
"keywords": [],
"author": "Elian Doran <contact@eliandoran.me>",
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.20.0",
"packageManager": "pnpm@10.21.0",
"devDependencies": {
"@redocly/cli": "2.11.0",
"@redocly/cli": "2.11.1",
"archiver": "7.0.1",
"fs-extra": "11.3.2",
"react": "19.2.0",

View File

@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.99.4",
"version": "0.99.5",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@ -43,7 +43,7 @@
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
"globals": "16.5.0",
"i18next": "25.6.1",
"i18next": "25.6.2",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",

View File

@ -329,6 +329,7 @@ export type CommandMappings = {
exportAsPdf: CommandData;
openNoteExternally: CommandData;
openNoteCustom: CommandData;
openNoteOnServer: CommandData;
renderActiveNote: CommandData;
unhoist: CommandData;
reloadFrontendApp: CommandData;

View File

@ -66,6 +66,13 @@ export default class RootCommandExecutor extends Component {
}
}
openNoteOnServerCommand() {
const noteId = appContext.tabManager.getActiveContextNoteId();
if (noteId) {
openService.openNoteOnServer(noteId);
}
}
enterProtectedSessionCommand() {
protectedSessionService.enterProtectedSession();
}

View File

@ -1,4 +1,5 @@
import utils from "./utils.js";
import options from "./options.js";
import server from "./server.js";
type ExecFunction = (command: string, cb: (err: string, stdout: string, stderror: string) => void) => void;
@ -171,6 +172,21 @@ function getHost() {
return `${url.protocol}//${url.hostname}:${url.port}`;
}
async function openNoteOnServer(noteId: string) {
// Get the sync server host from options
const syncServerHost = options.get("syncServerHost");
if (!syncServerHost) {
console.error("No sync server host configured");
return;
}
const url = new URL(`#root/${noteId}`, syncServerHost).toString();
// Use window.open to ensure link opens in external browser in Electron
window.open(url, '_blank', 'noopener,noreferrer');
}
async function openDirectory(directory: string) {
try {
if (utils.isElectron()) {
@ -198,5 +214,6 @@ export default {
openAttachmentExternally,
openNoteCustom,
openAttachmentCustom,
openNoteOnServer,
openDirectory
};

View File

@ -24,7 +24,9 @@ export async function formatCodeBlocks($container: JQuery<HTMLElement>) {
continue;
}
applyCopyToClipboardButton($(codeBlock));
if (glob.device !== "print") {
applyCopyToClipboardButton($(codeBlock));
}
if (syntaxHighlightingEnabled) {
applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType);

View File

@ -42,7 +42,7 @@ div.promoted-attributes-container {
*/
/* The property label */
.note-info-widget-table th,
.note-info-item > span:first-child,
.file-properties-widget .file-table th,
.image-properties > div:first-child > span > strong {
opacity: 0.65;
@ -50,7 +50,6 @@ div.promoted-attributes-container {
vertical-align: top;
}
.note-info-widget-table td,
.file-properties-widget .file-table td {
vertical-align: top;
}

View File

@ -682,6 +682,7 @@
"open_note_externally": "Open note externally",
"open_note_externally_title": "File will be open in an external application and watched for changes. You'll then be able to upload the modified version back to Trilium.",
"open_note_custom": "Open note custom",
"open_note_on_server": "Open note on server",
"import_files": "Import files",
"export_note": "Export note",
"delete_note": "Delete note",

View File

@ -39,7 +39,10 @@
"help_on_tree_prefix": "Ayuda sobre el prefijo del árbol",
"prefix": "Prefijo: ",
"save": "Guardar",
"branch_prefix_saved": "Se ha guardado el prefijo de rama."
"branch_prefix_saved": "Se ha guardado el prefijo de rama.",
"edit_branch_prefix_multiple": "Editar prefijo de rama para {{count}} ramas",
"branch_prefix_saved_multiple": "El prefijo de rama se ha guardado para {{count}} ramas.",
"affected_branches": "Ramas afectadas ({{count}}):"
},
"bulk_actions": {
"bulk_actions": "Acciones en bloque",
@ -1107,7 +1110,8 @@
"title": "Ancho del contenido",
"default_description": "Trilium limita de forma predeterminada el ancho máximo del contenido para mejorar la legibilidad de ventanas maximizadas en pantallas anchas.",
"max_width_label": "Ancho máximo del contenido en píxeles",
"max_width_unit": "píxeles"
"max_width_unit": "píxeles",
"centerContent": "Mantener el contenido centrado"
},
"native_title_bar": {
"title": "Barra de título nativa (requiere reiniciar la aplicación)",
@ -2079,5 +2083,14 @@
},
"collections": {
"rendering_error": "No se puede mostrar contenido debido a un error."
},
"read-only-info": {
"read-only-note": "Actualmente, está viendo una nota de solo lectura.",
"auto-read-only-note": "Esta nota se muestra en modo de solo lectura para una carga más rápida.",
"auto-read-only-learn-more": "Para saber más",
"edit-note": "Editar nota"
},
"calendar_view": {
"delete_note": "Eliminar nota..."
}
}

View File

@ -39,7 +39,10 @@
"help_on_tree_prefix": "Aiuto sui prefissi dell'Albero",
"prefix": "Prefisso: ",
"save": "Salva",
"branch_prefix_saved": "Il prefisso del ramo è stato salvato."
"branch_prefix_saved": "Il prefisso del ramo è stato salvato.",
"edit_branch_prefix_multiple": "Modifica prefisso ramo per {{count}} rami",
"branch_prefix_saved_multiple": "Il prefisso del ramo è stato salvato per {{count}} rami.",
"affected_branches": "Rami interessati ({{count}}):"
},
"bulk_actions": {
"bulk_actions": "Azioni massive",
@ -1499,7 +1502,7 @@
},
"protected_session": {
"enter_password_instruction": "Per visualizzare la nota protetta è necessario inserire la password:",
"start_session_button": "Avvia sessione protetta <kbd>invio</kbd>",
"start_session_button": "Avvia sessione protetta",
"started": "La sessione protetta è stata avviata.",
"wrong_password": "Password errata.",
"protecting-finished-successfully": "Protezione completata con successo.",
@ -1570,7 +1573,8 @@
"title": "Larghezza del contenuto",
"default_description": "Per impostazione predefinita, Trilium limita la larghezza massima del contenuto per migliorare la leggibilità sugli schermi più grandi.",
"max_width_label": "Larghezza massima del contenuto",
"max_width_unit": "pixel"
"max_width_unit": "pixel",
"centerContent": "Mantieni il contenuto centrato"
},
"native_title_bar": {
"title": "Barra del titolo nativa (richiede il riavvio dell'app)",
@ -2080,5 +2084,14 @@
},
"collections": {
"rendering_error": "Impossibile mostrare il contenuto a causa di un errore."
},
"read-only-info": {
"read-only-note": "Stai visualizzando una nota di sola lettura.",
"auto-read-only-note": "Questa nota viene visualizzata in modalità di sola lettura per un caricamento più rapido.",
"auto-read-only-learn-more": "Per saperne di più",
"edit-note": "Modifica nota"
},
"calendar_view": {
"delete_note": "Eliminazione nota..."
}
}

View File

@ -836,7 +836,8 @@
"title": "コンテンツ幅",
"default_description": "Triliumは、ワイドスクリーンで最大化された画面での可読性を向上させるために、デフォルトでコンテンツの最大幅を制限しています。",
"max_width_label": "最大コンテンツ幅",
"max_width_unit": "ピクセル"
"max_width_unit": "ピクセル",
"centerContent": "コンテンツを中央に配置"
},
"theme": {
"title": "アプリのテーマ",
@ -1783,7 +1784,7 @@
},
"protected_session": {
"enter_password_instruction": "保護されたノートを表示するにはパスワードを入力する必要があります:",
"start_session_button": "保護されたセッションを開始 <kbd>enter</kbd>",
"start_session_button": "保護されたセッションを開始",
"started": "保護されたセッションが開始されました。",
"wrong_password": "パスワードが間違っています。",
"protecting-finished-successfully": "保護が正常に完了しました。",
@ -2082,5 +2083,11 @@
},
"calendar_view": {
"delete_note": "ノートを削除..."
},
"read-only-info": {
"read-only-note": "現在、読み取り専用のノートを表示しています。",
"auto-read-only-note": "このノートは読み込みを高速化するために読み取り専用モードで表示されています。",
"auto-read-only-learn-more": "さらに詳しく",
"edit-note": "ノートを編集"
}
}

View File

@ -58,8 +58,6 @@ export async function changeEvent(note: FNote, { startDate, endDate, startTime,
startAttribute = note.getAttributes("label").filter(attr => attr.name == "calendar:startTime").shift()?.value||"startTime";
endAttribute = note.getAttributes("label").filter(attr => attr.name == "calendar:endTime").shift()?.value||"endTime";
if (startTime && endTime) {
setAttribute(note, "label", startAttribute, startTime);
setAttribute(note, "label", endAttribute, endTime);
}
setAttribute(note, "label", startAttribute, startTime);
setAttribute(note, "label", endAttribute, endTime);
}

View File

@ -7,6 +7,11 @@ import Container from "../containers/container.js";
const TPL = /*html*/`\
<div class="popup-editor-dialog modal fade mx-auto" tabindex="-1" role="dialog">
<style>
/** Reduce the z-index of modals so that ckeditor popups are properly shown on top of it. */
body.popup-editor-open > .modal-backdrop { z-index: 998; }
body.popup-editor-open .popup-editor-dialog { z-index: 999; }
body.popup-editor-open .ck-clipboard-drop-target-line { z-index: 1000; }
body.desktop .modal.popup-editor-dialog .modal-dialog {
max-width: 75vw;
}
@ -136,11 +141,6 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
}
$dialog.on("shown.bs.modal", async () => {
// Reduce the z-index of modals so that ckeditor popups are properly shown on top of it.
// The backdrop instance is not shared so it's OK to make a one-off modification.
$("body > .modal-backdrop").css("z-index", "998");
$dialog.css("z-index", "999");
await this.handleEventInChildren("activeContextChanged", { noteContext: this.noteContext });
this.setVisibility(true);
await this.handleEventInChildren("focusOnDetail", { ntxId: this.noteContext.ntxId });
@ -161,9 +161,12 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
if (visible) {
$bodyItems.fadeIn();
this.$modalHeader.children().show();
document.body.classList.add("popup-editor-open");
} else {
$bodyItems.hide();
this.$modalHeader.children().hide();
document.body.classList.remove("popup-editor-open");
}
}

View File

@ -6,9 +6,9 @@ export interface CKEditorApi {
focus(): void;
/**
* Imperatively sets the text in the editor.
*
*
* Prefer setting `currentValue` prop where possible.
*
*
* @param text text to set in the editor
*/
setText(text: string): void;
@ -27,15 +27,16 @@ interface CKEditorOpts {
onClick?: (e: MouseEvent, pos?: ModelPosition | null) => void;
onKeyDown?: (e: KeyboardEvent) => void;
onBlur?: () => void;
onInitialized?: (editorInstance: CKTextEditor) => void;
}
export default function CKEditor({ apiRef, currentValue, editor, config, disableNewlines, disableSpellcheck, onChange, onClick, ...restProps }: CKEditorOpts) {
const editorContainerRef = useRef<HTMLDivElement>(null);
export default function CKEditor({ apiRef, currentValue, editor, config, disableNewlines, disableSpellcheck, onChange, onClick, onInitialized, ...restProps }: CKEditorOpts) {
const editorContainerRef = useRef<HTMLDivElement>(null);
const textEditorRef = useRef<CKTextEditor>(null);
useImperativeHandle(apiRef, () => {
return {
focus() {
editorContainerRef.current?.focus();
textEditorRef.current?.editing.view.focus();
textEditorRef.current?.model.change((writer) => {
const documentRoot = textEditorRef.current?.editing.model.document.getRoot();
if (documentRoot) {
@ -83,6 +84,8 @@ export default function CKEditor({ apiRef, currentValue, editor, config, disable
if (currentValue) {
textEditor.setData(currentValue);
}
onInitialized?.(textEditor);
});
}, []);
@ -103,4 +106,4 @@ export default function CKEditor({ apiRef, currentValue, editor, config, disable
{...restProps}
/>
)
}
}

View File

@ -5,6 +5,7 @@ import { ParentComponent } from "../react/react_utils";
import { t } from "../../services/i18n"
import { useContext } from "preact/hooks";
import { useIsNoteReadOnly } from "../react/hooks";
import { useTriliumOption } from "../react/hooks";
import ActionButton from "../react/ActionButton"
import appContext, { CommandNames } from "../../components/app_context";
import branches from "../../services/branches";
@ -53,6 +54,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
const isMac = getIsMac();
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(note.type);
const isSearchOrBook = ["search", "book"].includes(note.type);
const [ syncServerHost ] = useTriliumOption("syncServerHost");
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
return (
@ -68,7 +70,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
command={() => enableEditing()} />
<FormDropdownDivider />
</>}
{canBeConvertedToAttachment && <ConvertToAttachment note={note} /> }
{note.type === "render" && <CommandItem command="renderActiveNote" icon="bx bx-extension" text={t("note_actions.re_render_note")} />}
<CommandItem command="findInText" icon="bx bx-search" disabled={!isSearchable} text={t("note_actions.search_in_note")} />
@ -90,6 +92,9 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
<CommandItem command="openNoteExternally" icon="bx bx-file-find" disabled={isSearchOrBook || !isElectron} text={t("note_actions.open_note_externally")} title={t("note_actions.open_note_externally_title")} />
<CommandItem command="openNoteCustom" icon="bx bx-customize" disabled={isSearchOrBook || isMac || !isElectron} text={t("note_actions.open_note_custom")} />
<CommandItem command="showNoteSource" icon="bx bx-code" disabled={!hasSource} text={t("note_actions.note_source")} />
{(syncServerHost && isElectron) &&
<CommandItem command="openNoteOnServer" icon="bx bx-world" disabled={!syncServerHost} text={t("note_actions.open_note_on_server")} />
}
<FormDropdownDivider />
<CommandItem command="forceSaveRevision" icon="bx bx-save" disabled={isInOptionsOrHelp} text={t("note_actions.save_revision")} />

View File

@ -36,57 +36,58 @@ export default function NoteInfoTab({ note }: TabContext) {
return (
<div className="note-info-widget">
{note && (
<table className="note-info-widget-table">
<tbody>
<tr>
<th>{t("note_info_widget.note_id")}:</th>
<td class="note-info-id">{note.noteId}</td>
<th>{t("note_info_widget.created")}:</th>
<td>{formatDateTime(metadata?.dateCreated)}</td>
<th>{t("note_info_widget.modified")}:</th>
<td>{formatDateTime(metadata?.dateModified)}</td>
</tr>
<>
<div className="note-info-item">
<span>{t("note_info_widget.note_id")}:</span>
<span className="note-info-id">{note.noteId}</span>
</div>
<div className="note-info-item">
<span>{t("note_info_widget.created")}:</span>
<span>{formatDateTime(metadata?.dateCreated)}</span>
</div>
<div className="note-info-item">
<span>{t("note_info_widget.modified")}:</span>
<span>{formatDateTime(metadata?.dateModified)}</span>
</div>
<div className="note-info-item">
<span>{t("note_info_widget.type")}:</span>
<span>
<span className="note-info-type">{note.type}</span>{' '}
{note.mime && <span className="note-info-mime">({note.mime})</span>}
</span>
</div>
<div className="note-info-item">
<span title={t("note_info_widget.note_size_info")}>{t("note_info_widget.note_size")}:</span>
<span className="note-info-size-col-span">
{!isLoading && !noteSizeResponse && !subtreeSizeResponse && (
<Button
className="calculate-button"
icon="bx bx-calculator"
text={t("note_info_widget.calculate")}
onClick={() => {
setIsLoading(true);
setTimeout(async () => {
await Promise.allSettled([
server.get<NoteSizeResponse>(`stats/note-size/${note.noteId}`).then(setNoteSizeResponse),
server.get<SubtreeSizeResponse>(`stats/subtree-size/${note.noteId}`).then(setSubtreeSizeResponse)
]);
setIsLoading(false);
}, 0);
}}
/>
)}
<tr>
<th>{t("note_info_widget.type")}:</th>
<td>
<span class="note-info-type">{note.type}</span>{' '}
{ note.mime && <span class="note-info-mime">({note.mime})</span> }
</td>
<th title={t("note_info_widget.note_size_info")}>{t("note_info_widget.note_size")}:</th>
<td colSpan={3}>
{!isLoading && !noteSizeResponse && !subtreeSizeResponse && (
<Button
className="calculate-button"
style={{ padding: "0px 10px 0px 10px" }}
icon="bx bx-calculator"
text={t("note_info_widget.calculate")}
onClick={() => {
setIsLoading(true);
setTimeout(async () => {
await Promise.allSettled([
server.get<NoteSizeResponse>(`stats/note-size/${note.noteId}`).then(setNoteSizeResponse),
server.get<SubtreeSizeResponse>(`stats/subtree-size/${note.noteId}`).then(setSubtreeSizeResponse)
]);
setIsLoading(false);
}, 0);
}}
/>
)}
<span className="note-sizes-wrapper">
<span class="note-size">{formatSize(noteSizeResponse?.noteSize)}</span>
{" "}
{subtreeSizeResponse && subtreeSizeResponse.subTreeNoteCount > 1 &&
<span class="subtree-size">{t("note_info_widget.subtree_size", { size: formatSize(subtreeSizeResponse.subTreeSize), count: subtreeSizeResponse.subTreeNoteCount })}</span>
}
{isLoading && <LoadingSpinner />}
</span>
</td>
</tr>
</tbody>
</table>
<span className="note-sizes-wrapper">
<span className="note-size">{formatSize(noteSizeResponse?.noteSize)}</span>
{" "}
{subtreeSizeResponse && subtreeSizeResponse.subTreeNoteCount > 1 &&
<span className="subtree-size">{t("note_info_widget.subtree_size", { size: formatSize(subtreeSizeResponse.subTreeSize), count: subtreeSizeResponse.subTreeNoteCount })}</span>
}
{isLoading && <LoadingSpinner />}
</span>
</span>
</div>
</>
)}
</div>
)

View File

@ -26,4 +26,4 @@ export default function OwnedAttributesTab({ note, hidden, activate, ntxId, ...r
)}
</div>
)
}
}

View File

@ -238,11 +238,6 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
}
});
// Focus on show.
useEffect(() => {
setTimeout(() => editorRef.current?.focus(), 0);
}, []);
// Interaction with CKEditor.
useLegacyImperativeHandlers(useMemo(() => ({
loadReferenceLinkTitle: async ($el: JQuery<HTMLElement>, href: string) => {
@ -363,6 +358,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
}}
onKeyDown={() => attributeDetailWidget.hide()}
onBlur={() => save()}
onInitialized={() => editorRef.current?.focus()}
disableNewlines disableSpellcheck
/>

View File

@ -160,17 +160,20 @@
/* #region Note info */
.note-info-widget {
padding: 12px;
display: flex;
flex-wrap: wrap;
align-items: baseline;
}
.note-info-widget-table {
max-width: 100%;
display: block;
overflow-x: auto;
white-space: nowrap;
.note-info-item {
display: flex;
align-items: baseline;
padding-inline-end: 15px;
padding-block: 5px;
}
.note-info-widget-table td, .note-info-widget-table th {
padding: 5px;
.note-info-item > span:first-child {
padding-inline-end: 5px;
}
.note-info-mime {
@ -186,6 +189,10 @@
font-size: 0.8em;
vertical-align: middle !important;
}
.note-info-widget .calculate-button {
padding: 0 10px;
}
/* #endregion */
/* #region Similar Notes */

View File

@ -108,6 +108,8 @@ const config: ForgeConfig = {
"--share=network",
// System notifications with libnotify
"--talk-name=org.freedesktop.Notifications",
// System tray
"--talk-name=org.kde.StatusNotifierWatcher"
],
modules: [
{

View File

@ -1,6 +1,6 @@
{
"name": "@triliumnext/desktop",
"version": "0.99.4",
"version": "0.99.5",
"description": "Build your personal knowledge base with Trilium Notes",
"private": true,
"main": "src/main.ts",
@ -16,7 +16,7 @@
"build": "tsx scripts/build.ts",
"start-prod": "pnpm build && cross-env TRILIUM_DATA_DIR=data TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
"electron-forge:make": "pnpm build && electron-forge make dist",
"electron-forge:make-flatpak": "pnpm build && electron-forge make dist --targets=@electron-forge/maker-flatpak",
"electron-forge:make-flatpak": "pnpm build && DEBUG=* electron-forge make dist --targets=@electron-forge/maker-flatpak",
"electron-forge:package": "pnpm build && electron-forge package dist",
"electron-forge:start": "pnpm build && electron-forge start dist",
"e2e": "pnpm build && cross-env TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=8082 TRILIUM_DATA_DIR=data-e2e ELECTRON_IS_DEV=0 playwright test"

View File

@ -38,11 +38,16 @@ async function main() {
app.commandLine.appendSwitch("disable-smooth-scrolling");
}
// Electron 36 crashes with "Using GTK 2/3 and GTK 4 in the same process is not supported" on some distributions.
// See https://github.com/electron/electron/issues/46538 for more info.
if (process.platform === "linux") {
app.setName(PRODUCT_NAME);
// Electron 36 crashes with "Using GTK 2/3 and GTK 4 in the same process is not supported" on some distributions.
// See https://github.com/electron/electron/issues/46538 for more info.
app.commandLine.appendSwitch("gtk-version", "3");
// Enable global shortcuts in Flatpak
// the app runs in a Wayland session.
app.commandLine.appendSwitch("enable-features", "GlobalShortcutsPortal");
}
// Quit when all windows are closed, except on macOS. There, it's common

View File

@ -1,6 +1,6 @@
{
"name": "@triliumnext/server",
"version": "0.99.4",
"version": "0.99.5",
"description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.",
"private": true,
"main": "./src/main.ts",
@ -97,7 +97,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "25.6.1",
"i18next": "25.6.2",
"i18next-fs-backend": "2.6.0",
"image-type": "6.0.0",
"ini": "6.0.0",

View File

@ -20,10 +20,10 @@ fi
# Debug output
echo "Selected Arch: $ARCH"
# Set Node.js version and architecture-specific filename
NODE_VERSION=22.16.0
script_dir=$(realpath $(dirname $0))
# Set Node.js version and architecture-specific filename
NODE_VERSION=$(cat "../../.nvmrc")
BUILD_DIR="$script_dir/../dist"
DIST_DIR="$script_dir/../out"

View File

@ -258,7 +258,9 @@
"user-guide": "Guía de Usuario",
"localization": "Idioma y Región",
"inbox-title": "Bandeja",
"jump-to-note-title": "Saltar a..."
"jump-to-note-title": "Saltar a...",
"command-palette": "Abrir paleta de comandos",
"zen-mode": "Modo Zen"
},
"notes": {
"new-note": "Nueva nota",
@ -424,7 +426,7 @@
"built-in-templates": "Plantillas predefinidas",
"board_status_todo": "Por hacer",
"board_status_done": "Hecho",
"board": "Tablero",
"board": "Tablero Kanban",
"presentation": "Presentación",
"presentation_slide": "Slide de presentación",
"presentation_slide_first": "Primer slide",

View File

@ -147,7 +147,9 @@
"settings-title": "Impostazioni",
"llm-chat-title": "Parla con Notes",
"note-launcher-title": "Scorciatoie delle note",
"script-launcher-title": "Scorciatoie degli script"
"script-launcher-title": "Scorciatoie degli script",
"command-palette": "Apri tavolozza comandi",
"zen-mode": "Modalità Zen"
},
"notes": {
"new-note": "Nuova nota",

View File

@ -343,7 +343,9 @@
"etapi-title": "ETAPI",
"visible-launchers-title": "可視化されたランチャー",
"inbox-title": "Inbox",
"base-abstract-launcher-title": "ベース アブストラクトランチャー"
"base-abstract-launcher-title": "ベース アブストラクトランチャー",
"command-palette": "コマンドパレットを開く",
"zen-mode": "禅モード"
},
"notes": {
"new-note": "新しいノート",

View File

@ -40,5 +40,9 @@
"open-new-window": "새 비어있는 창 열기",
"toggle-tray": "시스템 트레이에서 애플리케이션 보여주기/숨기기",
"tabs-and-windows": "탭 & 창"
},
"hidden-subtree": {
"zen-mode": "젠 모드",
"open-today-journal-note-title": "오늘의 일지 기록 열기"
}
}

View File

@ -159,7 +159,7 @@ function getEditedNotesOnDate(req: Request) {
SELECT noteId FROM notes
WHERE
(notes.dateCreated LIKE :date OR notes.dateModified LIKE :date)
AND (noteId NOT LIKE '_%')
AND (notes.noteId NOT LIKE '\\_%' ESCAPE '\\')
UNION ALL
SELECT noteId FROM revisions
WHERE revisions.dateCreated LIKE :date

View File

@ -9,7 +9,7 @@
"preview": "pnpm build && vite preview"
},
"dependencies": {
"i18next": "25.6.1",
"i18next": "25.6.2",
"i18next-http-backend": "3.0.2",
"preact": "10.27.2",
"preact-iso": "2.11.0",

View File

@ -1 +1,8 @@
{}
{
"get-started": {
"title": "Začínáme",
"desktop_title": "Stažení aplikace pro osobní počítače (v{{version}})",
"architecture": "Architektura:",
"older_releases": "Starší vydání"
}
}

View File

@ -17,7 +17,9 @@
"organization_benefits": {
"title": "Organisation",
"note_structure_title": "Notizstruktur",
"attributes_title": "Notiz Labels und Beziehungen"
"attributes_title": "Notiz Labels und Beziehungen",
"note_structure_description": "Notizen lassen sich hierarchisch anordnen. Ordner sind nicht nötig, da jede Notiz Unternotizen enthalten kann. Eine einzelne Notiz kann an mehreren Stellen in der Hierarchie hinzugefügt werden.",
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird."
},
"productivity_benefits": {
"revisions_title": "Notizrevisionen",
@ -26,7 +28,8 @@
"protected_notes_title": "Geschützte Notizen",
"jump_to_title": "Schnellsuche und Kommandos",
"search_title": "Leistungsstarke Suche",
"web_clipper_title": "Web clipper"
"web_clipper_title": "Web clipper",
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden."
},
"note_types": {
"text_title": "Text Notizen",

12
docs/README-cs.md vendored
View File

@ -20,13 +20,13 @@ releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
[![Translation
status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) |
[Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README-ru.md)
| [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) |
[Spanish](./docs/README-es.md)
[Angličtina](./README.md) | [Čínština (Zjednodušená)](./docs/README-ZH_CN.md) |
[Čínština (Tradiční)](./docs/README-ZH_TW.md) | [Ruština](./docs/README-ru.md) |
[Japonština](./docs/README-ja.md) | [Italština](./docs/README-it.md) |
[Španělština](./docs/README-es.md)
Trilium Notes is a free and open-source, cross-platform hierarchical note taking
application with focus on building large personal knowledge bases.
Trilium Notes je open-source, cross-platform aplikace pro hierarchiální psaní
poznámek.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
quick overview:

12
docs/README-nl.md vendored
View File

@ -34,12 +34,12 @@ voor een snel overzicht:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## Download
- [Laatse release](https://github.com/TriliumNext/Trilium/releases/latest) -
stabiele versie, aangeraden voor meeste gebruikers
- [Nachtige build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstabiele development versie, dagelijks geupdatet met de laatste functies
en oplossingen.
## 📚 Documentatie

View File

@ -61,6 +61,32 @@
"attachments": [],
"dirFileName": "Release Notes",
"children": [
{
"isClone": false,
"noteId": "7HKMTjmopLcM",
"notePath": [
"hD3V4hiu2VW4",
"7HKMTjmopLcM"
],
"title": "v0.99.5",
"notePosition": 10,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "template",
"value": "wyurrlcDl416",
"isInheritable": false,
"position": 60
}
],
"format": "markdown",
"dataFileName": "v0.99.5.md",
"attachments": []
},
{
"isClone": false,
"noteId": "RMBaNYPsRpIr",
@ -69,7 +95,7 @@
"RMBaNYPsRpIr"
],
"title": "v0.99.4",
"notePosition": 10,
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -95,7 +121,7 @@
"yuroLztFfpu5"
],
"title": "v0.99.3",
"notePosition": 20,
"notePosition": 30,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -121,7 +147,7 @@
"z207sehwMJ6C"
],
"title": "v0.99.2",
"notePosition": 30,
"notePosition": 40,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -147,7 +173,7 @@
"WGQsXq2jNyTi"
],
"title": "v0.99.1",
"notePosition": 40,
"notePosition": 50,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -173,7 +199,7 @@
"cyw2Yue9vXf3"
],
"title": "v0.99.0",
"notePosition": 50,
"notePosition": 60,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -199,7 +225,7 @@
"QOJwjruOUr4k"
],
"title": "v0.98.1",
"notePosition": 60,
"notePosition": 70,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -225,7 +251,7 @@
"PLUoryywi0BC"
],
"title": "v0.98.0",
"notePosition": 70,
"notePosition": 80,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -251,7 +277,7 @@
"lvOuiWsLDv8F"
],
"title": "v0.97.2",
"notePosition": 80,
"notePosition": 90,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -277,7 +303,7 @@
"OtFZ6Nd9vM3n"
],
"title": "v0.97.1",
"notePosition": 90,
"notePosition": 100,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -303,7 +329,7 @@
"SJZ5PwfzHSQ1"
],
"title": "v0.97.0",
"notePosition": 100,
"notePosition": 110,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -329,7 +355,7 @@
"mYXFde3LuNR7"
],
"title": "v0.96.0",
"notePosition": 110,
"notePosition": 120,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -355,7 +381,7 @@
"jthwbL0FdaeU"
],
"title": "v0.95.0",
"notePosition": 120,
"notePosition": 130,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -381,7 +407,7 @@
"7HGYsJbLuhnv"
],
"title": "v0.94.1",
"notePosition": 130,
"notePosition": 140,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -407,7 +433,7 @@
"Neq53ujRGBqv"
],
"title": "v0.94.0",
"notePosition": 140,
"notePosition": 150,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -433,7 +459,7 @@
"VN3xnce1vLkX"
],
"title": "v0.93.0",
"notePosition": 150,
"notePosition": 160,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -451,7 +477,7 @@
"WRaBfQqPr6qo"
],
"title": "v0.92.7",
"notePosition": 160,
"notePosition": 170,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -477,7 +503,7 @@
"a2rwfKNmUFU1"
],
"title": "v0.92.6",
"notePosition": 170,
"notePosition": 180,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -495,7 +521,7 @@
"fEJ8qErr0BKL"
],
"title": "v0.92.5-beta",
"notePosition": 180,
"notePosition": 190,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -513,7 +539,7 @@
"kkkZQQGSXjwy"
],
"title": "v0.92.4",
"notePosition": 190,
"notePosition": 200,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -531,7 +557,7 @@
"vAroNixiezaH"
],
"title": "v0.92.3-beta",
"notePosition": 200,
"notePosition": 210,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -549,7 +575,7 @@
"mHEq1wxAKNZd"
],
"title": "v0.92.2-beta",
"notePosition": 210,
"notePosition": 220,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -567,7 +593,7 @@
"IykjoAmBpc61"
],
"title": "v0.92.1-beta",
"notePosition": 220,
"notePosition": 230,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -585,7 +611,7 @@
"dq2AJ9vSBX4Y"
],
"title": "v0.92.0-beta",
"notePosition": 230,
"notePosition": 240,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -603,7 +629,7 @@
"3a8aMe4jz4yM"
],
"title": "v0.91.6",
"notePosition": 240,
"notePosition": 250,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -621,7 +647,7 @@
"8djQjkiDGESe"
],
"title": "v0.91.5",
"notePosition": 250,
"notePosition": 260,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -639,7 +665,7 @@
"OylxVoVJqNmr"
],
"title": "v0.91.4-beta",
"notePosition": 260,
"notePosition": 270,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -657,7 +683,7 @@
"tANGQDvnyhrj"
],
"title": "v0.91.3-beta",
"notePosition": 270,
"notePosition": 280,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -675,7 +701,7 @@
"hMoBfwSoj1SC"
],
"title": "v0.91.2-beta",
"notePosition": 280,
"notePosition": 290,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -693,7 +719,7 @@
"a2XMSKROCl9z"
],
"title": "v0.91.1-beta",
"notePosition": 290,
"notePosition": 300,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -711,7 +737,7 @@
"yqXFvWbLkuMD"
],
"title": "v0.90.12",
"notePosition": 300,
"notePosition": 310,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -729,7 +755,7 @@
"veS7pg311yJP"
],
"title": "v0.90.11-beta",
"notePosition": 310,
"notePosition": 320,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -747,7 +773,7 @@
"sq5W9TQxRqMq"
],
"title": "v0.90.10-beta",
"notePosition": 320,
"notePosition": 330,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -765,7 +791,7 @@
"yFEGVCUM9tPx"
],
"title": "v0.90.9-beta",
"notePosition": 330,
"notePosition": 340,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -783,7 +809,7 @@
"o4wAGqOQuJtV"
],
"title": "v0.90.8",
"notePosition": 340,
"notePosition": 350,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -816,7 +842,7 @@
"i4A5g9iOg9I0"
],
"title": "v0.90.7-beta",
"notePosition": 350,
"notePosition": 360,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -834,7 +860,7 @@
"ThNf2GaKgXUs"
],
"title": "v0.90.6-beta",
"notePosition": 360,
"notePosition": 370,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -852,7 +878,7 @@
"G4PAi554kQUr"
],
"title": "v0.90.5-beta",
"notePosition": 370,
"notePosition": 380,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -879,7 +905,7 @@
"zATRobGRCmBn"
],
"title": "v0.90.4",
"notePosition": 380,
"notePosition": 390,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -897,7 +923,7 @@
"sCDLf8IKn3Iz"
],
"title": "v0.90.3",
"notePosition": 390,
"notePosition": 400,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -915,7 +941,7 @@
"VqqyBu4AuTjC"
],
"title": "v0.90.2-beta",
"notePosition": 400,
"notePosition": 410,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -933,7 +959,7 @@
"RX3Nl7wInLsA"
],
"title": "v0.90.1-beta",
"notePosition": 410,
"notePosition": 420,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -951,7 +977,7 @@
"GyueACukPWjk"
],
"title": "v0.90.0-beta",
"notePosition": 420,
"notePosition": 430,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -969,7 +995,7 @@
"kzjHexDTTeVB"
],
"title": "v0.48",
"notePosition": 430,
"notePosition": 440,
"prefix": null,
"isExpanded": false,
"type": "text",
@ -1036,7 +1062,7 @@
"wyurrlcDl416"
],
"title": "Release Template",
"notePosition": 440,
"notePosition": 450,
"prefix": null,
"isExpanded": false,
"type": "text",

View File

@ -0,0 +1,24 @@
# v0.99.5
> [!NOTE]
> If you are interested in an [official mobile application](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/7447)  ([#7447](https://github.com/TriliumNext/Trilium/issues/7447)) or [multi-user support](https://oss.issuehunt.io/r/TriliumNext/Trilium/issues/4956) ([#4956](https://github.com/TriliumNext/Trilium/issues/4956)), consider offering financial support via IssueHunt (see links).
> [!IMPORTANT]
> If you enjoyed this release, consider showing a token of appreciation by:
>
> * Pressing the “Star” button on [GitHub](https://github.com/TriliumNext/Trilium) (top-right).
> * Considering a one-time or recurrent donation to the [lead developer](https://github.com/eliandoran) via [GitHub Sponsors](https://github.com/sponsors/eliandoran) or [PayPal](https://paypal.me/eliandoran).
## 🐞 Bugfixes
* [List view: weird animation + hard to toggle collapse/expand deeper nested subnotes](https://github.com/TriliumNext/Trilium/issues/7667) by @adoriandoran
* Code block “Copy to clipboard button” visible while printing.
* Packaged server .zip build not working due to wrong Node.js version.
* Not all changed notes are displayed in day note by @contributor
* [Calendar view drag-and-drop issue](https://github.com/TriliumNext/Trilium/issues/7685)
* ["Open attribute list" shortcut does not focus the attribute list](https://github.com/TriliumNext/Trilium/issues/7463)
* [Global shortcuts and system tray icon sometimes not shown under Wayland in Flatpak](https://github.com/TriliumNext/Trilium/issues/7563)
* [Quick edit text drag indicator missing](https://github.com/TriliumNext/Trilium/issues/7686)
## ✨ Improvements
* [Show collections grid and list views in zen mode](https://github.com/TriliumNext/Trilium/issues/7668) by @adoriandoran

View File

@ -1,6 +1,6 @@
{
"name": "@triliumnext/source",
"version": "0.99.4",
"version": "0.99.5",
"description": "Build your personal knowledge base with Trilium Notes",
"directories": {
"doc": "docs"
@ -49,7 +49,7 @@
"chalk": "5.6.2",
"cross-env": "10.1.0",
"dpdm": "3.14.0",
"esbuild": "0.25.12",
"esbuild": "0.27.0",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-playwright": "2.3.0",
@ -63,7 +63,7 @@
"tslib": "2.8.1",
"tsx": "4.20.6",
"typescript": "~5.9.0",
"typescript-eslint": "8.46.3",
"typescript-eslint": "8.46.4",
"upath": "2.0.1",
"vite": "7.2.2",
"vite-plugin-dts": "~4.5.0",
@ -83,7 +83,7 @@
"url": "https://github.com/TriliumNext/Trilium/issues"
},
"homepage": "https://triliumnotes.org",
"packageManager": "pnpm@10.20.0",
"packageManager": "pnpm@10.21.0",
"pnpm": {
"patchedDependencies": {
"@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch",

View File

@ -25,7 +25,7 @@
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "4.1.1",
"@typescript-eslint/eslint-plugin": "~8.46.0",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/parser": "8.46.4",
"@vitest/browser": "3.2.4",
"@vitest/coverage-istanbul": "3.2.4",
"ckeditor5": "47.2.0",

View File

@ -26,7 +26,7 @@
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "4.1.1",
"@typescript-eslint/eslint-plugin": "~8.46.0",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/parser": "8.46.4",
"@vitest/browser": "3.2.4",
"@vitest/coverage-istanbul": "3.2.4",
"ckeditor5": "47.2.0",

View File

@ -28,7 +28,7 @@
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "4.1.1",
"@typescript-eslint/eslint-plugin": "~8.46.0",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/parser": "8.46.4",
"@vitest/browser": "3.2.4",
"@vitest/coverage-istanbul": "3.2.4",
"ckeditor5": "47.2.0",

View File

@ -29,7 +29,7 @@
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "4.1.1",
"@typescript-eslint/eslint-plugin": "~8.46.0",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/parser": "8.46.4",
"@vitest/browser": "3.2.4",
"@vitest/coverage-istanbul": "3.2.4",
"ckeditor5": "47.2.0",

View File

@ -28,7 +28,7 @@
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "4.1.1",
"@typescript-eslint/eslint-plugin": "~8.46.0",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/parser": "8.46.4",
"@vitest/browser": "3.2.4",
"@vitest/coverage-istanbul": "3.2.4",
"ckeditor5": "47.2.0",

View File

@ -15,7 +15,7 @@
"ckeditor5-premium-features": "47.2.0"
},
"devDependencies": {
"@smithy/middleware-retry": "4.4.6",
"@smithy/middleware-retry": "4.4.7",
"@types/jquery": "3.5.33"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@triliumnext/commons",
"version": "0.99.4",
"version": "0.99.5",
"description": "Shared library between the clients (e.g. browser, Electron) and the server, mostly for type definitions and utility methods.",
"private": true,
"type": "module",

View File

@ -32,10 +32,10 @@
"devDependencies": {
"@digitak/esrun": "3.2.26",
"@triliumnext/ckeditor5": "workspace:*",
"@typescript-eslint/eslint-plugin": "8.46.3",
"@typescript-eslint/parser": "8.46.3",
"@typescript-eslint/eslint-plugin": "8.46.4",
"@typescript-eslint/parser": "8.46.4",
"dotenv": "17.2.3",
"esbuild": "0.25.12",
"esbuild": "0.27.0",
"eslint": "9.39.1",
"highlight.js": "11.11.1",
"typescript": "5.9.3"

1057
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff