diff --git a/.nxignore b/.nxignore index 7290b55e6..bac1baa0e 100644 --- a/.nxignore +++ b/.nxignore @@ -1,2 +1,7 @@ _regroup -_regroup_monorepo \ No newline at end of file +_regroup_monorepo + +# Asset copying respects .gitignore / .nxignore for some reason. +# See https://github.com/nrwl/nx/issues/20309 +!dist +!node_modules \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 60b3455da..86eca8e3a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,7 @@ }, "github-actions.workflows.pinned.workflows": [ ".github/workflows/nightly.yml" - ] + ], + "typescript.validate.enable": true, + "typescript.tsserver.experimental.enableProjectDiagnostics": true } \ No newline at end of file diff --git a/_regroup/package.json b/_regroup/package.json index 2db64c988..d45a40937 100644 --- a/_regroup/package.json +++ b/_regroup/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "@playwright/test": "1.52.0", - "@stylistic/eslint-plugin": "4.2.0", + "@stylistic/eslint-plugin": "4.4.0", "@types/express": "5.0.1", "@types/node": "22.15.21", "@types/yargs": "17.0.33", diff --git a/apps/client/package.json b/apps/client/package.json index 163f6297d..dd8caff50 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -63,7 +63,7 @@ "@types/leaflet": "1.9.18", "@types/leaflet-gpx": "1.3.7", "@types/mark.js": "8.11.12", - "@types/react": "19.1.4", + "@types/react": "19.1.5", "@types/react-dom": "19.1.5", "copy-webpack-plugin": "13.0.0", "happy-dom": "17.4.7", diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index bff0a333b..be1c8e717 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -1010,9 +1010,10 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href font-size: var(--detail-font-size) !important; } -.ck-mentions .ck-button.ck-on { - background-color: var(--active-item-background-color) !important; - color: var(--active-item-text-color) !important; +.ck-mentions { + --ck-color-list-button-on-background: var(--active-item-background-color); + --ck-color-list-button-on-background-focus: var(--ck-color-list-button-on-background); + --ck-color-list-button-on-text: var(--active-item-text-color); } .ck-mentions .ck-button b { diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index b49f9142a..031bdf465 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -5,6 +5,12 @@ * Color scheme */ :root { + + /* + * ⚠️ NOTICE: This theme is currently in the beta stage of development. + * The names and purposes of these CSS variables are subject to frequent changes. + */ + --theme-style: dark; --native-titlebar-background: #00000000; @@ -89,6 +95,7 @@ --menu-item-arrow-color: #ffffffa3; --menu-item-delimiter-color: #ffffff1c; --menu-item-group-header-color: #ffffff91; + --menu-section-background-color: #fefefe08; --modal-backdrop-color: #000; --modal-shadow-color: rgba(0, 0, 0, .5); @@ -236,6 +243,11 @@ --help-code-background: #565656; --ck-editor-popup-border-color: var(--modal-border-color); + + --ck-editor-toolbar-button-on-background: #ffffff3b; + --ck-editor-toolbar-button-on-color: white; + --ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75); + --ck-editor-toolbar-dropdown-button-open-background: #ffffff14; } /* diff --git a/apps/client/src/stylesheets/theme-next-light.css b/apps/client/src/stylesheets/theme-next-light.css index bdf3ae228..ba994587f 100644 --- a/apps/client/src/stylesheets/theme-next-light.css +++ b/apps/client/src/stylesheets/theme-next-light.css @@ -5,6 +5,12 @@ * Color scheme */ :root { + + /* + * ⚠️ NOTICE: This theme is currently in the beta stage of development. + * The names and purposes of these CSS variables are subject to frequent changes. + */ + --theme-style: light; --native-titlebar-background: #ffffff00; @@ -83,6 +89,7 @@ --menu-item-arrow-color: #00000080; --menu-item-delimiter-color: #00000030; --menu-item-group-header-color: #00000061; + --menu-section-background-color: #00000006; --modal-backdrop-color: #7c7c7c; --modal-shadow-color: #00000033; @@ -236,4 +243,9 @@ --help-code-background: #d7d5d5; --ck-editor-popup-border-color: var(--dropdown-border-color); + --ck-editor-toolbar-button-on-background: #00000030; + --ck-editor-toolbar-button-on-color: black; + --ck-editor-toolbar-button-on-shadow: none; + --ck-editor-toolbar-dropdown-button-open-background: #0000000f; + } diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index e9917b142..9058328c3 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -110,7 +110,8 @@ body.mobile .dropdown-menu .dropdown-menu { border-radius: unset !important; } -body.desktop .dropdown-menu::before { +body.desktop .dropdown-menu::before, +:root .ck.ck-dropdown__panel::before { content: ""; backdrop-filter: var(--dropdown-backdrop-filter); border-radius: var(--dropdown-border-radius); diff --git a/apps/client/src/stylesheets/theme-next/forms.css b/apps/client/src/stylesheets/theme-next/forms.css index f7aa04831..c83b70522 100644 --- a/apps/client/src/stylesheets/theme-next/forms.css +++ b/apps/client/src/stylesheets/theme-next/forms.css @@ -79,7 +79,7 @@ button.btn.btn-success kbd { */ :root .icon-action:not(.global-menu-button), -:root .tn-tool-button, +:root .btn.tn-tool-button, :root .btn-group .tn-tool-button:not(:last-child), :root .btn-group .tn-tool-button:last-child { width: var(--icon-button-size); diff --git a/apps/client/src/stylesheets/theme-next/notes/text.css b/apps/client/src/stylesheets/theme-next/notes/text.css index 769ba5699..2d9127fd4 100644 --- a/apps/client/src/stylesheets/theme-next/notes/text.css +++ b/apps/client/src/stylesheets/theme-next/notes/text.css @@ -10,7 +10,8 @@ * Toolbar */ -.ck.ck-toolbar { +.ck.ck-toolbar, +.ck.ck-block-toolbar-button { --ck-color-toolbar-background: transparent; --ck-color-button-default-background: transparent; @@ -19,19 +20,62 @@ --ck-color-button-on-background: transparent; --ck-color-button-on-hover-background: var(--hover-item-background-color); + --ck-color-button-default-active-background: var(--hover-item-background-color); - --ck-focus-ring: 1px solid var(--input-focus-outline-color); + --ck-color-split-button-hover-background: var(--ck-editor-toolbar-dropdown-button-open-background); + + --ck-focus-ring: 1px solid transparent; --ck-color-focus-border: var(--input-focus-outline-color); --ck-focus-outer-shadow: none; + --ck-focus-disabled-outer-shadow: none; --ck-border-radius: 6px; } +/* Toolbar button in on state */ +.ck.ck-toolbar .ck-button.ck-on:not(.ck-dropdown__button):not(.ck-list-item-button):not(.ck-button_with-text) { + --ck-color-button-on-background: var(--ck-editor-toolbar-button-on-background); + --ck-color-button-on-color: var(--ck-editor-toolbar-button-on-color); + box-shadow: var(--ck-editor-toolbar-button-on-shadow); +} + +/* Toolbar button with its dropdown open */ +.ck.ck-toolbar .ck-button.ck-dropdown__button { + --ck-color-button-on-background: var(--ck-editor-toolbar-dropdown-button-open-background); + --ck-color-button-on-color: currentColor; +} + +/* The toolbar show / hide button for the current text block */ +.ck.ck-block-toolbar-button { + --ck-color-button-on-background: transparent; + --ck-color-button-on-color: currentColor; +} + +:root .ck.ck-toolbar .ck-button:not(.ck-disabled):active, +.ck.ck-block-toolbar-button:active { + background-color: var(--hover-item-background-color); +} + +.ck.ck-toolbar .ck-button:active:not(.ck-list-item-button):not(.ck-button_with-text):not(.ck-disabled) svg:not(.ck-dropdown__arrow), +.ck.ck-block-toolbar-button:active svg { + transform: scale(.8); +} + /* Disabled button */ :root .classic-toolbar-widget .ck.ck-button.ck-disabled { opacity: .75; } +/* Focus visible */ +.ck.ck-toolbar .ck-button:focus-visible { + --ck-focus-ring: 1px solid var(--input-focus-outline-color); +} + +/* Remove the border from hovered split arrow button */ +.ck.ck-splitbutton:hover > .ck-splitbutton__arrow:not(.ck-disabled)::after { + visibility: collapse; +} + /* * Dropdowns */ @@ -49,16 +93,61 @@ border: 1px solid var(--ck-editor-popup-border-color) !important; border-radius: var(--dropdown-border-radius) !important; background: var(--menu-background-color) !important; - backdrop-filter: var(--dropdown-backdrop-filter); padding: var(--ck-editor-popup-padding); } +/* + * Backdrop blur pseudo-element + * + * Since .ck-balloon-panel already uses the :after and :before pseudo-elements, there is no other + * option than using a :before on the children element to apply the backdrop blur. + * This pseudoelement will overflow and cover the entire surface of .ck-balloon-panel. +*/ + +:root .ck-balloon-panel > .ck-toolbar, +:root .ck-balloon-panel > .ck-balloon-rotator { + position: relative; +} + +:root .ck-balloon-panel > .ck-toolbar::before, +:root .ck-balloon-panel > .ck-balloon-rotator::before { + --negative-padding: calc(0px - var(--ck-editor-popup-padding)); /* Compensate the parent's padding */ + + content: ""; + position: absolute; + top: var(--negative-padding); + right: var(--negative-padding); + bottom: var(--negative-padding); + left: var(--negative-padding); + border-radius: var(--dropdown-border-radius); + backdrop-filter: var(--dropdown-backdrop-filter); + z-index: -1; +} + +:root .ck.ck-dropdown__panel { + --ck-editor-popup-padding: var(--menu-padding-size); +} + +/* Dropdown panel containing a toolbar */ +:root .ck.ck-dropdown__panel:has(>.ck-toolbar) { + --ck-editor-popup-padding: calc(var(--menu-padding-size) - var(--ck-spacing-small)); +} + +/* Bulleted / number list toolbar */ +.ck-list-styles-list { + --ck-spacing-large: var(--ck-spacing-small); +} + :root ul.ck.ck-list, :root div.ck.ck-balloon-panel:not(.ck-tooltip) { border: none; background: transparent; } +:root .ck.ck-list { + padding: 0; +} + /* Tooltip */ :root div.ck.ck-balloon-panel.ck-tooltip { --ck-color-panel-background: var(--toast-background); /* Arrow */ @@ -81,6 +170,15 @@ box-shadow: unset; } +:root .ck.ck-list__item { + min-width: 10em; +} + +/* Item with icon */ +:root .ck.ck-button_with-text svg:first-child { + color: var(--menu-item-icon-color); +} + /* Checked list item */ :root ul.ck.ck-list button.ck-button:hover, @@ -91,6 +189,18 @@ color: var(--hover-item-color); } +/* List item checkmark container */ + +:root .ck.ck-list-item-button .ck-list-item-button__check-holder { + margin-inline-start: var(--ck-spacing-small); + margin-inline-end: var(--menu-padding-size); +} + +:root .ck.ck-list-item-button .ck-list-item-button__check-holder svg { + transform: scale(1.2); + color: var(--menu-item-icon-color); +} + /* Separator */ :root .ck .ck-list__separator { margin: .5em 0; @@ -119,8 +229,8 @@ bottom: var(--negative-padding); left: var(--negative-padding); right: var(--negative-padding); - border-top: 1px solid var(--ck-color-base-border); - background: rgba(0, 0, 0, .025); + border-top: 1px solid var(--ck-editor-popup-border-color); + background: var(--menu-section-background-color); } .ck.ck-collapsible:last-child::before { @@ -135,6 +245,24 @@ padding-top: 1em; } +/* Toolbar separators */ + +:root .ck.ck-toolbar .ck.ck-toolbar__separator { + background: transparent; + border-left: 1px solid var(--ck-color-toolbar-border); +} + +/* The last separator of the toolbar */ +:root .classic-toolbar-widget .ck.ck-toolbar__separator:last-of-type { + flex-grow: 1; +} + +/* Heading dropdown */ + +:root .ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item { + min-width: 170px; +} + /* Font size dropdown */ .ck-fontsize-option { @@ -152,6 +280,11 @@ /* Color picker dropdown */ +/* Color palette */ +:root .ck.ck-color-selector .ck-color-grid { + --ck-editor-toolbar-button-on-shadow: none; /* Remove the shadow of the selected color button */ +} + /* Color picker button */ :root .ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker { --ck-color-base-border: transparent; /* Remove the top border */ @@ -160,8 +293,27 @@ border-bottom-right-radius: var(--ck-border-radius); } +/* Current color checkmark */ +:root .ck.ck-color-selector .ck-color-grid .ck-icon { + color: white; +} + +:root .ck.ck-color-selector .ck-color-grid .ck-icon__fill { + fill: black !important; +} + +/* Numbered list */ + +:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list { + min-width: 200px; + grid-template-columns: repeat(3, auto); + justify-content: space-between; + padding-bottom: calc(var(--ck-spacing-medium) + var(--menu-padding-size)); +} + /* Table dropdown */ +/* Table rows / columns button grid container */ .ck-insert-table-dropdown__grid { --ck-insert-table-dropdown-box-width: 16px; --ck-insert-table-dropdown-box-height: 16px; @@ -170,6 +322,12 @@ --ck-color-focus-border: var(--hover-item-text-color); /* Selected cell box border color */ --ck-color-focus-outer-shadow: var(--hover-item-background-color); /* Selected cell box background color */ --ck-border-radius: 0; + --ck-editor-toolbar-button-on-shadow: 1px 1px 1px rgba(0, 0, 0, .35); +} + +/* Selected rows / column counter */ +.ck.ck-insert-table-dropdown__label { + margin-top: var(--ck-spacing-medium); } /* Admonitions dropdown */ @@ -215,6 +373,20 @@ background: var(--hover-item-background-color); } +/* Mention list (the autocompletion list for emojis, labels and relations) */ + +:root .ck-mentions { + --ck-color-list-button-on-background: var(--hover-item-background-color); + --ck-color-list-button-on-text: var(--hover-item-text-color); + --ck-color-list-button-hover-background: var(--ck-editor-toolbar-dropdown-button-open-background); + --ck-focus-ring: 1px solid transparent; +} + +/* "Keep on typing to see the emoji" placeholder */ +#mention-list-item-id\:__EMOJI_HINT { + background: transparent; +} + /* * EDITOR'S CONTENT */ diff --git a/apps/client/src/widgets/dialogs/note_type_chooser.ts b/apps/client/src/widgets/dialogs/note_type_chooser.ts index 5e9b7bdf1..927e2f174 100644 --- a/apps/client/src/widgets/dialogs/note_type_chooser.ts +++ b/apps/client/src/widgets/dialogs/note_type_chooser.ts @@ -110,6 +110,8 @@ export default class NoteTypeChooserDialog extends BasicWidget { //@ts-ignore if (e.clickEvent) { e.preventDefault(); + } else { + this.modal.hide(); } }); } diff --git a/apps/db-compare/package.json b/apps/db-compare/package.json index c4d6620c4..370ae38a6 100644 --- a/apps/db-compare/package.json +++ b/apps/db-compare/package.json @@ -5,7 +5,7 @@ "description": "Tool to compare content of Trilium databases. Useful for debugging sync problems.", "dependencies": { "colors": "1.4.0", - "diff": "8.0.1", + "diff": "8.0.2", "sqlite": "5.1.1", "sqlite3": "5.1.7" }, diff --git a/apps/db-compare/src/sql.ts b/apps/db-compare/src/sql.ts index 9e165ceab..adb03e4eb 100644 --- a/apps/db-compare/src/sql.ts +++ b/apps/db-compare/src/sql.ts @@ -51,8 +51,8 @@ async function getMap(db: Database, query: string, params: any[] = []) { return map; } -async function getFlattenedResults(db: Database, key: string, query: string, params: any[] = []) { - const list = []; +async function getFlattenedResults(db: Database, key: string, query: string, params: any[] = []) { + const list: T[] = []; const result = await getResults(db, query, params); for (const row of result) { diff --git a/apps/desktop/.swcrc b/apps/desktop/.swcrc deleted file mode 100644 index a2d5b04f4..000000000 --- a/apps/desktop/.swcrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "jsc": { - "parser": { - "syntax": "typescript" - }, - "target": "es2016" - } -} diff --git a/apps/desktop/electron-forge/forge.config.cjs b/apps/desktop/electron-forge/forge.config.cjs index 3f81bb477..b9fb0dd79 100644 --- a/apps/desktop/electron-forge/forge.config.cjs +++ b/apps/desktop/electron-forge/forge.config.cjs @@ -68,8 +68,8 @@ module.exports = { ] }, rebuildConfig: { - force: true, - extraModules: [ "better-sqlite3" ] + force: false, + onlyModules: [] }, makers: [ { diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 71b61fcce..77833046b 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Build your personal knowledge base with TriliumNext Notes", "private": true, - "main": "main.js", + "main": "main.cjs", "dependencies": { "@electron/remote": "2.1.2", "better-sqlite3": "^11.9.1", @@ -17,7 +17,7 @@ "@types/electron-squirrel-startup": "1.0.2", "@triliumnext/server": "workspace:*", "copy-webpack-plugin": "13.0.0", - "electron": "36.2.1", + "electron": "36.3.1", "@electron-forge/cli": "7.8.1", "@electron-forge/maker-deb": "7.8.1", "@electron-forge/maker-dmg": "7.8.1", @@ -29,7 +29,7 @@ "prebuild-install": "^7.1.1" }, "config": { - "forge": "../electron-forge/forge.config.cjs" + "forge": "./electron-forge/forge.config.cjs" }, "packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977", "scripts": { @@ -44,6 +44,69 @@ "nx": { "name": "desktop", "targets": { + "build": { + "executor": "@nx/esbuild:esbuild", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "main": "apps/desktop/src/electron-main.ts", + "outputPath": "apps/desktop/dist", + "outputFileName": "main.js", + "tsConfig": "apps/desktop/tsconfig.app.json", + "platform": "node", + "external": [ + "electron", + "@electron/remote", + "better-sqlite3", + "./xhr-sync-worker.js" + ], + "format": [ + "cjs" + ], + "minify": true, + "thirdParty": true, + "esbuildOptions": { + "splitting": false, + "loader": { + ".css": "text" + } + }, + "assets": [ + { + "glob": "**/*", + "input": "apps/server/dist/node_modules", + "output": "node_modules" + }, + { + "glob": "**/*", + "input": "apps/desktop/node_modules/@electron/remote", + "output": "node_modules/@electron/remote" + }, + { + "glob": "**/*", + "input": "apps/server/dist/assets", + "output": "assets" + }, + { + "glob": "**/*", + "input": "apps/desktop/src/assets", + "output": "assets" + }, + { + "glob": "**/*", + "input": "apps/server/dist/public", + "output": "public" + }, + { + "glob": "xhr-sync-worker.js", + "input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr", + "output": "" + } + ], + "declarationRootDir": "apps/desktop/src" + } + }, "rebuild-deps": { "executor": "nx:run-commands", "dependsOn": [ @@ -68,11 +131,11 @@ "defaultConfiguration": "default", "configurations": { "default": { - "command": "electron .", + "command": "electron main.cjs", "cwd": "{projectRoot}/dist" }, "nixos": { - "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"", + "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"", "cwd": ".", "forwardAllArgs": false } @@ -86,11 +149,11 @@ "defaultConfiguration": "default", "configurations": { "default": { - "command": "electron .", + "command": "electron main.cjs", "cwd": "{projectRoot}/dist" }, "nixos": { - "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"", + "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"", "cwd": ".", "forwardAllArgs": false } @@ -98,16 +161,25 @@ }, "electron-forge:make": { "dependsOn": [ - "build" + "build", + "rebuild-deps" ], "command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist" }, "electron-forge:package": { "dependsOn": [ - "build" + "build", + "rebuild-deps" ], "command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge package dist" + }, + "electron-forge:start": { + "dependsOn": [ + "build", + "rebuild-deps" + ], + "command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm TRILIUM_DATA_DIR=./data electron-forge start dist" } } } -} +} \ No newline at end of file diff --git a/apps/desktop/src/electron-main.ts b/apps/desktop/src/electron-main.ts index ac1c712dc..8a9ebae03 100644 --- a/apps/desktop/src/electron-main.ts +++ b/apps/desktop/src/electron-main.ts @@ -44,7 +44,7 @@ async function main() { await import("@triliumnext/server/src/main.js"); } -export async function onReady() { +async function onReady() { // electron.app.setAppUserModelId('com.github.zadam.trilium'); // if db is not initialized -> setup process diff --git a/apps/desktop/tsconfig.app.json b/apps/desktop/tsconfig.app.json index 8a23da03c..1c37e3a04 100644 --- a/apps/desktop/tsconfig.app.json +++ b/apps/desktop/tsconfig.app.json @@ -1,17 +1,21 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ES2020", "outDir": "dist", + "strict": false, "types": [ "node", "express" ], "rootDir": "src", - "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo", - "verbatimModuleSyntax": false + "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo" }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "../server/src/*.d.ts" ], "exclude": [ "eslint.config.js", diff --git a/apps/desktop/webpack.config.cjs b/apps/desktop/webpack.config.cjs deleted file mode 100644 index edd32780a..000000000 --- a/apps/desktop/webpack.config.cjs +++ /dev/null @@ -1,67 +0,0 @@ -const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); -const { join } = require('path'); - -const outputDir = join(__dirname, 'dist'); - -module.exports = { - output: { - path: outputDir, - }, - module: { - rules: [ - { - test: /\.css$/i, - type: "asset/source" - } - ] - }, - target: [ "node" ], - plugins: [ - new NxAppWebpackPlugin({ - target: 'node', - compiler: 'tsc', - main: './src/electron-main.ts', - tsConfig: './tsconfig.app.json', - assets: ["./src/assets"], - optimization: false, - outputHashing: 'none', - generatePackageJson: false, - externalDependencies: [ - "electron/main", - "@electron/remote/main", - "electron", - "@electron/remote", - "better-sqlite3" - ] - }), - new CopyPlugin({ - patterns: [ - { - from: "../client/dist", - to: join(outputDir, "public") - }, - { - from: "../server/dist/node_modules", - to: join(outputDir, "node_modules") - }, - { - from: "../server/dist/assets", - to: join(outputDir, "assets") - }, - { - from: "node_modules/@electron/remote", - to: join(outputDir, "node_modules/@electron/remote") - }, - { - from: "node_modules/prebuild-install", - to: join(outputDir, "node_modules/better-sqlite3/node_modules/prebuild-install") - }, - { - from: "package.json", - to: join(outputDir, "package.json") - } - ] - }) - ] -}; diff --git a/apps/edit-docs/package.json b/apps/edit-docs/package.json index d38029b5f..44dc9e910 100644 --- a/apps/edit-docs/package.json +++ b/apps/edit-docs/package.json @@ -3,12 +3,16 @@ "version": "0.0.1", "private": true, "description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.", + "dependencies": { + "archiver": "7.0.1", + "better-sqlite3": "^11.9.1" + }, "devDependencies": { "@triliumnext/client": "workspace:*", "@triliumnext/desktop": "workspace:*", "@types/fs-extra": "11.0.4", "copy-webpack-plugin": "13.0.0", - "electron": "36.2.1", + "electron": "36.3.1", "fs-extra": "11.3.0" }, "nx": { @@ -17,6 +21,59 @@ "server" ], "targets": { + "build": { + "executor": "@nx/esbuild:esbuild", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "main": "apps/edit-docs/src/electron-docs-main.ts", + "outputPath": "apps/edit-docs/dist", + "outputFileName": "main.js", + "tsConfig": "apps/edit-docs/tsconfig.app.json", + "platform": "node", + "external": [ + "electron", + "@electron/remote", + "better-sqlite3", + "./xhr-sync-worker.js" + ], + "format": [ + "cjs" + ], + "minify": true, + "thirdParty": true, + "esbuildOptions": { + "splitting": false, + "loader": { + ".css": "text" + } + }, + "assets": [ + { + "glob": "**/*", + "input": "apps/server/dist/node_modules", + "output": "node_modules" + }, + { + "glob": "**/*", + "input": "apps/server/dist/assets", + "output": "assets" + }, + { + "glob": "**/*", + "input": "apps/server/dist/public", + "output": "public" + }, + { + "glob": "xhr-sync-worker.js", + "input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr", + "output": "" + } + ], + "declarationRootDir": "apps/edit-docs/src" + } + }, "rebuild-deps": { "executor": "nx:run-commands", "dependsOn": [ @@ -41,19 +98,34 @@ "defaultConfiguration": "default", "configurations": { "default": { - "command": "electron .", - "cwd": "./apps/edit-docs/dist" + "command": "electron main.cjs", + "cwd": "{projectRoot}/dist" }, "nixos": { - "command": "nix-shell -p electron_35 --run \"electron .\"", - "forwardAllArgs": false, - "cwd": "./apps/edit-docs/dist" + "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"", + "cwd": ".", + "forwardAllArgs": false + } + } + }, + "serve-nodir": { + "executor": "nx:run-commands", + "dependsOn": [ + "rebuild-deps" + ], + "defaultConfiguration": "default", + "configurations": { + "default": { + "command": "electron main.cjs", + "cwd": "{projectRoot}/dist" + }, + "nixos": { + "command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"", + "cwd": ".", + "forwardAllArgs": false } } } } - }, - "dependencies": { - "archiver": "7.0.1" - } -} + } +} \ No newline at end of file diff --git a/apps/edit-docs/src/electron-docs-main.ts b/apps/edit-docs/src/electron-docs-main.ts index 52121df3a..7f293af49 100644 --- a/apps/edit-docs/src/electron-docs-main.ts +++ b/apps/edit-docs/src/electron-docs-main.ts @@ -13,8 +13,9 @@ import TaskContext from "@triliumnext/server/src/services/task_context.js"; import { deferred } from "@triliumnext/server/src/services/utils.js"; import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js"; import { resolve } from "path"; +import type NoteMeta from "@triliumnext/server/src/services/meta/note_meta.js"; import electron from "electron"; -import { onReady } from "@triliumnext/desktop/src/electron-main.js"; +import windowService from "@triliumnext/server/src/services/window.js"; interface NoteMapping { rootNoteId: string; @@ -55,12 +56,25 @@ const NOTE_MAPPINGS: NoteMapping[] = [ ]; async function main() { - electron.app.on("ready", onReady); + const initializedPromise = deferred(); + electron.app.on("ready", async () => { + await initializedPromise; + + console.log("Electron is ready!"); + + // Start the server. + await import("@triliumnext/server/src/main.js"); + + // Create the main window. + await windowService.createMainWindow(electron.app); + + // Wait for the import to be finished and the application to be loaded before we listen to changes. + setTimeout(() => registerHandlers(), 10_000); + }); await initializeTranslations(); await initializeDatabase(true); - const initializedPromise = deferred(); cls.init(async () => { for (const mapping of NOTE_MAPPINGS) { if (!mapping.exportOnly) { @@ -70,11 +84,6 @@ async function main() { setOptions(); initializedPromise.resolve(); }); - - await initializedPromise; - - // Wait for the import to be finished and the application to be loaded before we listen to changes. - setTimeout(() => registerHandlers(), 10_000); } async function setOptions() { diff --git a/apps/edit-docs/src/electron-edit-demo.ts b/apps/edit-docs/src/electron-edit-demo.ts index 17fb59e57..204e9220a 100644 --- a/apps/edit-docs/src/electron-edit-demo.ts +++ b/apps/edit-docs/src/electron-edit-demo.ts @@ -40,4 +40,4 @@ async function exportData() { await exportToZipFile("root", "html", DEMO_ZIP_PATH); } -await main(); +main(); diff --git a/apps/edit-docs/tsconfig.app.json b/apps/edit-docs/tsconfig.app.json index 2479661aa..b9e17115a 100644 --- a/apps/edit-docs/tsconfig.app.json +++ b/apps/edit-docs/tsconfig.app.json @@ -1,16 +1,21 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ES2020", "outDir": "dist", + "strict": false, "types": [ - "node" + "node", + "express" ], "rootDir": "src", - "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo", - "verbatimModuleSyntax": false + "tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo" }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "../server/src/*.d.ts" ], "exclude": [ "eslint.config.js", diff --git a/apps/edit-docs/webpack.config.cjs b/apps/edit-docs/webpack.config.cjs deleted file mode 100644 index 1ae774de7..000000000 --- a/apps/edit-docs/webpack.config.cjs +++ /dev/null @@ -1,53 +0,0 @@ -const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); -const { join } = require('path'); - -const outputDir = join(__dirname, 'dist'); - -module.exports = { - output: { - path: join(__dirname, 'dist'), - }, - module: { - rules: [ - { - test: /\.css$/i, - type: "asset/source" - } - ] - }, - plugins: [ - new NxAppWebpackPlugin({ - target: 'node', - compiler: 'tsc', - main: './src/electron-docs-main.ts', - tsConfig: './tsconfig.app.json', - optimization: false, - outputHashing: 'none', - generatePackageJson: true, - externalDependencies: [ - "electron/main", - "@electron/remote/main", - "electron", - "@electron/remote", - "better-sqlite3" - ] - }), - new CopyPlugin({ - patterns: [ - { - from: "../desktop/dist/node_modules", - to: join(outputDir, "node_modules") - }, - { - from: "../desktop/dist/assets", - to: join(outputDir, "assets") - }, - { - from: "../desktop/dist/public", - to: join(outputDir, "public") - }, - ] - }) - ], -}; diff --git a/apps/server-e2e/playwright.config.ts b/apps/server-e2e/playwright.config.ts index 43abab319..75de90147 100644 --- a/apps/server-e2e/playwright.config.ts +++ b/apps/server-e2e/playwright.config.ts @@ -26,7 +26,8 @@ export default defineConfig({ command: 'pnpm server:start-prod', url: baseURL, reuseExistingServer: !process.env.CI, - cwd: workspaceRoot + cwd: workspaceRoot, + timeout: 5 * 60 * 1000 } : undefined, projects: [ { diff --git a/apps/server/.serve.env b/apps/server/.serve.env index 5006a3765..43591d92c 100644 --- a/apps/server/.serve.env +++ b/apps/server/.serve.env @@ -1,3 +1,4 @@ TRILIUM_ENV=dev TRILIUM_DATA_DIR=./apps/server/data +TRILIUM_RESOURCE_DIR=./apps/server/dist TRILIUM_PUBLIC_SERVER=http://localhost:4200 \ No newline at end of file diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile index af4a95c94..1e357f6fe 100644 --- a/apps/server/Dockerfile +++ b/apps/server/Dockerfile @@ -1,13 +1,13 @@ -FROM node:22.15.1-bullseye-slim AS builder +FROM node:22.16.0-bullseye-slim AS builder RUN corepack enable # Install native dependencies since we might be building cross-platform. WORKDIR /usr/src/app/build - COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/ + COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/ # We have to use --no-frozen-lockfile due to CKEditor patches RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild -FROM node:22.15.1-bullseye-slim +FROM node:22.16.0-bullseye-slim # Install only runtime dependencies RUN apt-get update && \ apt-get install -y --no-install-recommends \ @@ -25,4 +25,4 @@ FROM node:22.15.1-bullseye-slim # Configure container EXPOSE 8080 CMD [ "sh", "./start-docker.sh" ] - HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.js \ No newline at end of file + HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs \ No newline at end of file diff --git a/apps/server/Dockerfile.alpine b/apps/server/Dockerfile.alpine index cf293e037..24d0dcb12 100644 --- a/apps/server/Dockerfile.alpine +++ b/apps/server/Dockerfile.alpine @@ -1,13 +1,13 @@ -FROM node:22.15.1-alpine AS builder +FROM node:22.16.0-alpine AS builder RUN corepack enable # Install native dependencies since we might be building cross-platform. WORKDIR /usr/src/app - COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/ + COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/ # We have to use --no-frozen-lockfile due to CKEditor patches RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild -FROM node:22.15.1-alpine +FROM node:22.16.0-alpine # Install runtime dependencies RUN apk add --no-cache su-exec shadow @@ -23,4 +23,4 @@ FROM node:22.15.1-alpine # Configure container EXPOSE 8080 CMD [ "sh", "./start-docker.sh" ] - HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.js \ No newline at end of file + HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs \ No newline at end of file diff --git a/apps/server/docker/package.json b/apps/server/docker/package.json new file mode 100644 index 000000000..bd414d937 --- /dev/null +++ b/apps/server/docker/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "better-sqlite3": "11.10.0" + } +} \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index fbc9d50a5..df48848cc 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -11,7 +11,7 @@ "@types/archiver": "6.0.3", "@types/better-sqlite3": "7.6.13", "@types/cls-hooked": "4.3.9", - "@types/compression": "1.7.5", + "@types/compression": "1.8.0", "@types/cookie-parser": "1.4.8", "@types/debounce": "1.2.4", "@types/ejs": "3.1.5", @@ -39,7 +39,7 @@ "@types/ws": "8.18.1", "@types/xml2js": "0.4.14", "express-http-proxy": "2.1.1", - "@anthropic-ai/sdk": "0.51.0", + "@anthropic-ai/sdk": "0.52.0", "@braintree/sanitize-url": "7.1.1", "@triliumnext/commons": "workspace:*", "@triliumnext/express-partial-content": "workspace:*", @@ -59,7 +59,7 @@ "debounce": "2.2.0", "debug": "4.4.1", "ejs": "3.1.10", - "electron": "36.2.1", + "electron": "36.3.1", "electron-debug": "4.1.0", "electron-window-state": "5.0.3", "escape-html": "1.0.3", @@ -88,7 +88,7 @@ "multer": "2.0.0", "normalize-strings": "1.1.1", "ollama": "0.5.15", - "openai": "4.100.0", + "openai": "4.103.0", "rand-token": "1.0.1", "safe-compare": "1.1.4", "sanitize-filename": "1.6.3", @@ -105,38 +105,21 @@ "tmp": "0.2.3", "turndown": "7.2.0", "unescape": "1.0.1", - "webpack": "5.99.9", "ws": "8.18.2", "xml2js": "0.6.2", - "yauzl": "3.2.0", - "copy-webpack-plugin": "13.0.0" + "yauzl": "3.2.0" }, "nx": { "name": "server", "targets": { - "build": { - "dependsOn": [ - "^build", - "client:build" - ] - }, "serve": { "executor": "@nx/js:node", - "defaultConfiguration": "development", "dependsOn": [ - "build" + "build-without-client" ], "options": { - "buildTarget": "server:build", + "buildTarget": "server:build-without-client:development", "runBuildTargetDependencies": false - }, - "configurations": { - "development": { - "buildTarget": "server:build:development" - }, - "production": { - "buildTarget": "server:build:production" - } } }, "package": { @@ -149,7 +132,7 @@ "dependsOn": [ "build" ], - "command": "node apps/server/dist/main.js" + "command": "node apps/server/dist/main.cjs" }, "docker-build": { "dependsOn": [ @@ -183,7 +166,118 @@ "command": "docker run -p 8081:8080 triliumnext-alpine" } } + }, + "build-without-client": { + "executor": "@nx/esbuild:esbuild", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "main": "apps/server/src/main.ts", + "outputPath": "apps/server/dist", + "outputFileName": "main.js", + "tsConfig": "apps/server/tsconfig.app.json", + "platform": "node", + "format": [ + "cjs" + ], + "declarationRootDir": "apps/server/src" + }, + "configurations": { + "development": { + "minify": false, + "assets": [ + { + "glob": "**/*", + "input": "apps/server/src/assets", + "output": "assets" + } + ] + } + } + }, + "build": { + "executor": "@nx/esbuild:esbuild", + "outputs": [ + "{options.outputPath}" + ], + "dependsOn": [ + "^build", + "client:build" + ], + "options": { + "main": "apps/server/src/main.ts", + "outputPath": "apps/server/dist", + "tsConfig": "apps/server/tsconfig.app.json", + "platform": "node", + "external": [ + "electron", + "@electron/remote", + "better-sqlite3", + "./xhr-sync-worker.js" + ], + "format": [ + "cjs" + ], + "declarationRootDir": "apps/server/src", + "minify": true, + "thirdParty": true, + "esbuildOptions": { + "splitting": false, + "loader": { + ".css": "text" + } + }, + "additionalEntryPoints": [ + "apps/server/src/docker_healthcheck.ts" + ], + "assets": [ + { + "glob": "**/*", + "input": "apps/server/src/assets", + "output": "assets" + }, + { + "glob": "**/*", + "input": "apps/client/dist", + "output": "public" + }, + { + "glob": "**/*", + "input": "apps/server/node_modules/better-sqlite3", + "output": "node_modules/better-sqlite3" + }, + { + "glob": "**/*", + "input": "apps/server/node_modules/bindings", + "output": "node_modules/bindings" + }, + { + "glob": "**/*", + "input": "apps/server/node_modules/file-uri-to-path", + "output": "node_modules/file-uri-to-path" + }, + { + "glob": "xhr-sync-worker.js", + "input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr", + "output": "" + } + ] + } } } - } + }, + "exports": { + "./package.json": "./package.json", + "./src/*": "./src/*", + ".": { + "development": "./src/main.ts", + "types": "./dist/main.d.ts", + "import": "./dist/main.js", + "default": "./dist/main.js" + } + }, + "types": "./dist/main.d.ts", + "module": "./dist/main.js", + "main": "./dist/main.js" } \ No newline at end of file diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index b48c7ced8..3ac3ee5c4 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -137,7 +137,7 @@ export default async function buildApp() { startScheduledCleanup(); if (utils.isElectron) { - (await import("@electron/remote/main")).initialize(); + (await import("@electron/remote/main/index.js")).initialize(); } return app; diff --git a/apps/server/src/assets/views/login.ejs b/apps/server/src/assets/views/login.ejs index 01efc8720..1daf91a3d 100644 --- a/apps/server/src/assets/views/login.ejs +++ b/apps/server/src/assets/views/login.ejs @@ -21,7 +21,7 @@