desktop: finalize new desktop core

This commit is contained in:
Abdullah Atta
2023-06-09 17:57:12 +05:00
committed by Abdullah Atta
parent 28927e705b
commit 6ab0911970
41 changed files with 2123 additions and 566 deletions

View File

@@ -8,19 +8,20 @@
"name": "@notesnook/desktop",
"version": "2.5.2",
"dependencies": {
"@trpc/client": "^10.18.0",
"@trpc/server": "^10.18.0",
"@trpc/client": "^10.29.1",
"@trpc/server": "^10.29.1",
"diary": "^0.3.1",
"electron-trpc": "^0.4.2",
"electron-trpc": "^0.5.0",
"electron-updater": "^5.3.0",
"icojs": "^0.17.1",
"typed-emitter": "^2.1.0",
"yargs": "^17.6.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@electron/rebuild": "^3.2.10",
"@electron/rebuild": "^3.2.13",
"@types/node": "^18.15.0",
"electron": "^25.1.0",
"electron": "^24.4.0",
"electron-builder": "^23.6.0",
"electron-builder-notarize": "^1.5.1",
"electron-reloader": "^1.2.3",
@@ -173,6 +174,7 @@
},
"node_modules/@electron/get": {
"version": "2.0.2",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^4.1.1",
@@ -191,9 +193,10 @@
}
},
"node_modules/@electron/rebuild": {
"version": "3.2.10",
"version": "3.2.13",
"resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.2.13.tgz",
"integrity": "sha512-DH9Ol4JCnHDYVOD0fKWq+Qqbn/0WU1O6QR0mIpMXEVU4YFM4PlaqNC9K36mGShNBxxGFotZCMDrB1wl/iHM12g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@malept/cross-spawn-promise": "^2.0.0",
"chalk": "^4.0.0",
@@ -201,7 +204,6 @@
"detect-libc": "^2.0.1",
"fs-extra": "^10.0.0",
"got": "^11.7.0",
"lzma-native": "^8.0.5",
"node-abi": "^3.0.0",
"node-api-version": "^0.1.4",
"node-gyp": "^9.0.0",
@@ -211,7 +213,7 @@
"yargs": "^17.0.1"
},
"bin": {
"electron-rebuild": "lib/src/cli.js"
"electron-rebuild": "lib/cli.js"
},
"engines": {
"node": ">=12.13.0"
@@ -799,6 +801,7 @@
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -809,6 +812,7 @@
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"dev": true,
"license": "MIT",
"dependencies": {
"defer-to-connect": "^2.0.0"
@@ -830,18 +834,27 @@
}
},
"node_modules/@trpc/client": {
"version": "10.18.0",
"license": "MIT",
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.29.1.tgz",
"integrity": "sha512-+9Tifg6dtKsYLsqOW0wizqc3iILAkXxn16pyYAeMDPlulPEqNvnI85GDJ0zJOJLIkQnQefkRbtCmtDxLNtV9Eg==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.18.0"
"@trpc/server": "10.29.1"
}
},
"node_modules/@trpc/server": {
"version": "10.18.0",
"license": "MIT"
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.29.1.tgz",
"integrity": "sha512-kNXgMh5ya+awuz2tB4eIyVrRs7nVtqGXwSGabzH3l5ZLWz7rbKJquOJ7h6bjvIfWUpaFG62HJNWxxGUtXCRgRw==",
"funding": [
"https://trpc.io/sponsor"
]
},
"node_modules/@types/cacheable-request": {
"version": "6.0.3",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/http-cache-semantics": "*",
@@ -878,10 +891,12 @@
},
"node_modules/@types/http-cache-semantics": {
"version": "4.0.1",
"dev": true,
"license": "MIT"
},
"node_modules/@types/keyv": {
"version": "3.1.4",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -900,6 +915,7 @@
},
"node_modules/@types/node": {
"version": "18.15.11",
"dev": true,
"license": "MIT"
},
"node_modules/@types/normalize-package-data": {
@@ -909,6 +925,7 @@
},
"node_modules/@types/responselike": {
"version": "1.0.0",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -933,6 +950,7 @@
},
"node_modules/@types/yauzl": {
"version": "2.10.0",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1273,6 +1291,7 @@
},
"node_modules/boolean": {
"version": "3.2.0",
"dev": true,
"license": "MIT",
"optional": true
},
@@ -1335,6 +1354,7 @@
},
"node_modules/buffer-crc32": {
"version": "0.2.13",
"dev": true,
"license": "MIT",
"engines": {
"node": "*"
@@ -1512,6 +1532,7 @@
},
"node_modules/cacheable-lookup": {
"version": "5.0.4",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.6.0"
@@ -1519,6 +1540,7 @@
},
"node_modules/cacheable-request": {
"version": "7.0.2",
"dev": true,
"license": "MIT",
"dependencies": {
"clone-response": "^1.0.2",
@@ -1638,6 +1660,7 @@
},
"node_modules/clone-response": {
"version": "1.0.3",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-response": "^1.0.0"
@@ -1777,6 +1800,7 @@
},
"node_modules/decompress-response": {
"version": "6.0.0",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-response": "^3.1.0"
@@ -1790,6 +1814,7 @@
},
"node_modules/decompress-response/node_modules/mimic-response": {
"version": "3.1.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -1811,6 +1836,7 @@
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -1818,6 +1844,7 @@
},
"node_modules/define-properties": {
"version": "1.2.0",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1862,6 +1889,7 @@
},
"node_modules/detect-node": {
"version": "2.1.0",
"dev": true,
"license": "MIT",
"optional": true
},
@@ -1981,9 +2009,10 @@
}
},
"node_modules/electron": {
"version": "25.1.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-25.1.0.tgz",
"integrity": "sha512-VKk4G/0euO7ysMKQKHXmI4d3/qR4uHsAtVFXK2WfQUVxBmc160OAm2R6PN9/EXmgXEioKQBtbc2/lvWyYpDbuA==",
"version": "24.5.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-24.5.0.tgz",
"integrity": "sha512-9Xo2EFZHWeuw1otm9mcJYKCNC64fPRpgp+ZJWMJ9RtvsnSgcuitkM4esZv4gIsqhWk5yiKApYHqinIUyu82O0Q==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@electron/get": "^2.0.0",
@@ -2253,8 +2282,12 @@
}
},
"node_modules/electron-trpc": {
"version": "0.4.2",
"license": "MIT",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.5.0.tgz",
"integrity": "sha512-xvnvOpuI0IiecMGS9VOS5/3kLj6IUpjngKhv5VqXU9vP2LzE140G8gqaziX0Tl7MaiYmJZbad/imis9i49n/4A==",
"dependencies": {
"debug": "^4.3.4"
},
"peerDependencies": {
"@trpc/client": ">10.0.0",
"@trpc/server": ">10.0.0",
@@ -2333,6 +2366,7 @@
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"dev": true,
"license": "MIT",
"dependencies": {
"once": "^1.4.0"
@@ -2340,6 +2374,7 @@
},
"node_modules/env-paths": {
"version": "2.2.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -2360,6 +2395,7 @@
},
"node_modules/es6-error": {
"version": "4.1.1",
"dev": true,
"license": "MIT",
"optional": true
},
@@ -2409,6 +2445,7 @@
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -2432,6 +2469,7 @@
},
"node_modules/extract-zip": {
"version": "2.0.1",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"debug": "^4.1.1",
@@ -2460,6 +2498,7 @@
},
"node_modules/fd-slicer": {
"version": "1.1.0",
"dev": true,
"license": "MIT",
"dependencies": {
"pend": "~1.2.0"
@@ -2543,6 +2582,7 @@
},
"node_modules/fs-extra": {
"version": "8.1.0",
"dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -2571,7 +2611,7 @@
},
"node_modules/function-bind": {
"version": "1.1.1",
"devOptional": true,
"dev": true,
"license": "MIT"
},
"node_modules/gauge": {
@@ -2601,6 +2641,7 @@
},
"node_modules/get-intrinsic": {
"version": "1.2.0",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2614,6 +2655,7 @@
},
"node_modules/get-stream": {
"version": "5.2.0",
"dev": true,
"license": "MIT",
"dependencies": {
"pump": "^3.0.0"
@@ -2657,6 +2699,7 @@
},
"node_modules/global-agent": {
"version": "3.0.0",
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"dependencies": {
@@ -2673,6 +2716,7 @@
},
"node_modules/global-agent/node_modules/semver": {
"version": "7.3.8",
"dev": true,
"license": "ISC",
"optional": true,
"dependencies": {
@@ -2687,6 +2731,7 @@
},
"node_modules/globalthis": {
"version": "1.0.3",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2701,6 +2746,7 @@
},
"node_modules/got": {
"version": "11.8.6",
"dev": true,
"license": "MIT",
"dependencies": {
"@sindresorhus/is": "^4.0.0",
@@ -2733,7 +2779,7 @@
},
"node_modules/has": {
"version": "1.0.3",
"devOptional": true,
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.1"
@@ -2752,6 +2798,7 @@
},
"node_modules/has-property-descriptors": {
"version": "1.0.0",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -2763,6 +2810,7 @@
},
"node_modules/has-symbols": {
"version": "1.0.3",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -2790,6 +2838,7 @@
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/http-proxy-agent": {
@@ -2807,6 +2856,7 @@
},
"node_modules/http2-wrapper": {
"version": "1.0.3",
"dev": true,
"license": "MIT",
"dependencies": {
"quick-lru": "^5.1.1",
@@ -3094,6 +3144,7 @@
},
"node_modules/json-buffer": {
"version": "3.0.1",
"dev": true,
"license": "MIT"
},
"node_modules/json-parse-even-better-errors": {
@@ -3108,6 +3159,7 @@
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"dev": true,
"license": "ISC",
"optional": true
},
@@ -3124,6 +3176,7 @@
},
"node_modules/jsonfile": {
"version": "4.0.0",
"dev": true,
"license": "MIT",
"optionalDependencies": {
"graceful-fs": "^4.1.6"
@@ -3131,6 +3184,7 @@
},
"node_modules/keyv": {
"version": "4.5.2",
"dev": true,
"license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
@@ -3197,6 +3251,7 @@
},
"node_modules/lowercase-keys": {
"version": "2.0.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3212,23 +3267,6 @@
"node": ">=10"
}
},
"node_modules/lzma-native": {
"version": "8.0.6",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^3.1.0",
"node-gyp-build": "^4.2.1",
"readable-stream": "^3.6.0"
},
"bin": {
"lzmajs": "bin/lzmajs"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/make-fetch-happen": {
"version": "10.2.1",
"dev": true,
@@ -3265,6 +3303,7 @@
},
"node_modules/matcher": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -3326,6 +3365,7 @@
},
"node_modules/mimic-response": {
"version": "1.0.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -3462,9 +3502,10 @@
"license": "MIT"
},
"node_modules/node-abi": {
"version": "3.33.0",
"version": "3.44.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.44.0.tgz",
"integrity": "sha512-MYjZTiAETGG28/7fBH1RjuY7vzDwYC5q5U4whCgM4jNEQcC0gAvN339LxXukmL2T2tGpzYTfp+LZ5RN7E5DwEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"semver": "^7.3.5"
},
@@ -3486,11 +3527,6 @@
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "3.2.1",
"dev": true,
"license": "MIT"
},
"node_modules/node-api-version": {
"version": "0.1.4",
"dev": true,
@@ -3536,16 +3572,6 @@
"node": "^12.13 || ^14.13 || >=16"
}
},
"node_modules/node-gyp-build": {
"version": "4.6.0",
"dev": true,
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/node-gyp/node_modules/semver": {
"version": "7.3.8",
"dev": true,
@@ -3608,6 +3634,7 @@
},
"node_modules/normalize-url": {
"version": "6.1.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -3632,6 +3659,7 @@
},
"node_modules/object-keys": {
"version": "1.1.1",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
@@ -3640,6 +3668,7 @@
},
"node_modules/once": {
"version": "1.4.0",
"dev": true,
"license": "ISC",
"dependencies": {
"wrappy": "1"
@@ -3706,6 +3735,7 @@
},
"node_modules/p-cancelable": {
"version": "2.1.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3980,6 +4010,7 @@
},
"node_modules/pend": {
"version": "1.2.0",
"dev": true,
"license": "MIT"
},
"node_modules/picomatch": {
@@ -4014,6 +4045,7 @@
},
"node_modules/progress": {
"version": "2.0.3",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@@ -4038,6 +4070,7 @@
},
"node_modules/pump": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
"dependencies": {
"end-of-stream": "^1.1.0",
@@ -4054,6 +4087,7 @@
},
"node_modules/quick-lru": {
"version": "5.1.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -4229,10 +4263,12 @@
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"dev": true,
"license": "MIT"
},
"node_modules/responselike": {
"version": "2.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"lowercase-keys": "^2.0.0"
@@ -4277,6 +4313,7 @@
},
"node_modules/roarr": {
"version": "2.15.4",
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"dependencies": {
@@ -4336,6 +4373,7 @@
},
"node_modules/semver": {
"version": "6.3.0",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -4343,11 +4381,13 @@
},
"node_modules/semver-compare": {
"version": "1.0.0",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/serialize-error": {
"version": "7.0.1",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -4362,6 +4402,7 @@
},
"node_modules/serialize-error/node_modules/type-fest": {
"version": "0.13.1",
"dev": true,
"license": "(MIT OR CC0-1.0)",
"optional": true,
"engines": {
@@ -4509,6 +4550,7 @@
},
"node_modules/sprintf-js": {
"version": "1.1.2",
"dev": true,
"license": "BSD-3-Clause",
"optional": true
},
@@ -4586,6 +4628,7 @@
},
"node_modules/sumchecker": {
"version": "3.0.1",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.1.0"
@@ -4783,6 +4826,7 @@
},
"node_modules/universalify": {
"version": "0.1.2",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
@@ -4861,6 +4905,7 @@
},
"node_modules/wrappy": {
"version": "1.0.2",
"dev": true,
"license": "ISC"
},
"node_modules/xmlbuilder": {
@@ -4915,6 +4960,7 @@
},
"node_modules/yauzl": {
"version": "2.10.0",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-crc32": "~0.2.3",

View File

@@ -11,19 +11,20 @@
"repository": "https://github.com/streetwriters/notesnook",
"dependencies": {
"@notesnook/crypto": "*",
"@trpc/client": "^10.18.0",
"@trpc/server": "^10.18.0",
"@trpc/client": "^10.29.1",
"@trpc/server": "^10.29.1",
"diary": "^0.3.1",
"electron-trpc": "^0.4.2",
"electron-trpc": "^0.5.0",
"electron-updater": "^5.3.0",
"icojs": "^0.17.1",
"yargs": "^17.6.2",
"zod": "^3.21.4"
"zod": "^3.21.4",
"typed-emitter": "^2.1.0"
},
"devDependencies": {
"@electron/rebuild": "^3.2.10",
"@electron/rebuild": "^3.2.13",
"@types/node": "^18.15.0",
"electron": "^25.1.0",
"electron": "^24.4.0",
"electron-builder": "^23.6.0",
"electron-builder-notarize": "^1.5.1",
"electron-reloader": "^1.2.3",
@@ -32,12 +33,12 @@
"undici": "^5.22.1"
},
"scripts": {
"start": "npm run build:electron && electron build/electron.js",
"start": "turbowatch scripts/dev.ts",
"staging": "zx scripts/staging.mjs",
"build": "tsc",
"build:electron": "esbuild electron=./src/main.ts ./src/preload.ts --external:electron --external:fsevents --minify --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=false --define:RELEASE=true",
"build:mas": "esbuild ./electron.js ./preload.js --minify --external:electron --external:fsevents --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=true --define:RELEASE=true",
"pack": "rm -rf ./build && cp -r ../build ./ && npm run build && yarn electron-builder --linux AppImage:x64 AppImage:arm64",
"postinstall": "patch-package"
"postinstall": "electron-builder install-app-deps && patch-package"
},
"author": {
"name": "Streetwriters (Private) Limited",
@@ -53,8 +54,8 @@
"!*.chunk.js.map",
"!*.chunk.js.LICENSE.txt",
"build/",
"!build/screenshots",
"!node_modules"
"!build/screenshots${/*}",
"!node_modules${/*}"
],
"afterSign": "electron-builder-notarize",
"afterPack": "./scripts/removeLocales.js",
@@ -185,7 +186,7 @@
],
"directories": {
"buildResources": "assets",
"output": "./dist/"
"output": "./output/"
},
"publish": [
{

117
apps/desktop/scripts/dev.ts Normal file
View File

@@ -0,0 +1,117 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import path from "path";
import fs from "fs/promises";
import { watch } from "turbowatch";
import { $, within } from "zx";
const sodiumNativePrebuildPath = path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`
);
let isServerRunning = false;
async function main() {
const { shutdown } = await watch({
project: path.join(__dirname, ".."),
cwd: path.join(__dirname, ".."),
triggers: [
{
expression: [
"allof",
["not", ["dirname", "node_modules"]],
["match", "*.ts", "basename"]
],
name: "dev",
// retry: { retries: 0 },
onTeardown: async () => {
await fs.rm("./build/", { force: true, recursive: true });
},
onChange: async ({ spawn: $, first, log }) => {
if (first) {
await fs.rm("./build/", { force: true, recursive: true });
}
await $`npm run build:electron`;
await $`tsc`;
if (first) {
await fs.cp(sodiumNativePrebuildPath, "build/prebuilds", {
recursive: true,
force: true
});
}
if (!isServerRunning) {
await spawnAndWaitUntil(
path.join(__dirname, "..", "..", "web"),
"npm run start:desktop",
(data) => data.includes("Compiled successfully!")
);
isServerRunning = true;
}
log("Starting desktop app!");
await $`npx electron ${path.join("build", "electron.js")}`;
}
}
]
});
// SIGINT is the signal sent when we press Ctrl+C
process.once("SIGINT", () => {
void shutdown();
});
}
main();
function spawnAndWaitUntil(
cwd: string,
cmd: string,
predicate: (data: string) => boolean
) {
return new Promise((resolve) => {
within(async () => {
$.env = process.env;
$.quote = (c) => c;
try {
const s = $`cd ${cwd} && ${cmd}`;
s.stdout.on("data", (data) => {
if (predicate(data)) resolve(undefined); //
});
await s;
} catch (e) {
//ignore
} finally {
isServerRunning = false;
}
});
});
}

View File

@@ -0,0 +1,65 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import path from "path";
import fs from "fs/promises";
import { $, argv, os } from "zx";
$.env = process.env;
const sodiumNativePrebuildPath = path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`,
`${os.platform()}-x64`
);
await fs.rm("./build/", { force: true, recursive: true });
if (argv.rebuild) await $`cd ../web/ && npm run build:desktop`;
await fs.cp(path.join("..", "web", "build"), "build", {
recursive: true,
force: true
});
await $`npm run build:electron`;
await $`tsc`;
await $`npm rebuild`;
await fs.cp(
sodiumNativePrebuildPath,
path.join("build", "prebuilds", `${process.platform}-x64`),
{
recursive: true,
force: true
}
);
if (argv.run) {
await $`yarn electron-builder -c.extraMetadata.main=./build/electron.js --linux AppImage:x64`;
await $`./output/notesnook_linux_x86_64.AppImage`;
}

View File

@@ -0,0 +1,58 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { initTRPC } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { EventEmitter } from "events";
import TypedEventEmitter from "typed-emitter";
export type AppEvents = {
onCreateItem(name: "note" | "notebook" | "reminder"): void;
};
const emitter = new EventEmitter();
const typedEmitter = emitter as TypedEventEmitter<AppEvents>;
const t = initTRPC.create();
export const bridgeRouter = t.router({
onCreateItem: createSubscription("onCreateItem")
});
export const bridge: AppEvents = new Proxy({} as AppEvents, {
get(_t, name) {
if (typeof name === "symbol") return;
return (...args: unknown[]) => {
emitter.emit(name, ...args);
};
}
});
function createSubscription<TName extends keyof AppEvents>(eventName: TName) {
return t.procedure.subscription(() => {
return observable<Parameters<AppEvents[TName]>[0]>((emit) => {
const listener: AppEvents[TName] = (...args: any[]) => {
emit.next(args[0]);
};
typedEmitter.addListener(eventName, listener);
return () => {
typedEmitter.removeListener(eventName, listener);
};
});
});
}

View File

@@ -22,6 +22,7 @@ import { compressionRouter } from "./compression";
import { osIntegrationRouter } from "./os-integration";
import { spellCheckerRouter } from "./spell-checker";
import { updaterRouter } from "./updater";
import { bridgeRouter } from "./bridge";
const t = initTRPC.create();
@@ -29,7 +30,8 @@ export const router = t.router({
compress: compressionRouter,
integration: osIntegrationRouter,
spellChecker: spellCheckerRouter,
updater: updaterRouter
updater: updaterRouter,
bridge: bridgeRouter
});
export const api = router.createCaller({});

View File

@@ -19,16 +19,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { initTRPC } from "@trpc/server";
import { z } from "zod";
import { dialog, Notification, shell } from "electron";
import { dialog, nativeTheme, Notification, shell } from "electron";
import { AutoLaunch } from "../utils/autolaunch";
import { config, DesktopIntegration } from "../utils/config";
import { bringToFront } from "../utils/bring-to-front";
import { setTheme, Theme } from "../utils/theme";
import { getTheme, setTheme, Theme } from "../utils/theme";
import { mkdirSync, writeFileSync } from "fs";
import { dirname, join } from "path";
import { platform } from "os";
import { resolvePath } from "../utils/resolve-path";
import { client } from "../rpc/electron";
import { observable } from "@trpc/server/observable";
const t = initTRPC.create();
@@ -132,7 +132,10 @@ export const osIntegrationRouter = t.router({
shell.beep();
}
client.onNotificationClicked(input.tag);
return new Promise((resolve) => {
notification.once("close", () => resolve(undefined));
notification.once("click", () => resolve(input.tag));
});
}),
openPath: t.procedure
.input(z.object({ type: z.literal("path"), link: z.string() }))
@@ -141,5 +144,17 @@ export const osIntegrationRouter = t.router({
if (type === "path") return shell.openPath(resolvePath(link));
}),
bringToFront: t.procedure.query(() => bringToFront()),
changeTheme: t.procedure.input(Theme).mutation(({ input }) => setTheme(input))
changeTheme: t.procedure
.input(Theme)
.mutation(({ input }) => setTheme(input)),
onThemeChanged: t.procedure.subscription(() =>
observable<"dark" | "light">((emit) => {
nativeTheme.on("updated", () => {
if (getTheme() === "system") {
emit.next(nativeTheme.shouldUseDarkColors ? "dark" : "light");
}
});
})
)
});

View File

@@ -18,7 +18,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { initTRPC } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { CancellationToken, autoUpdater } from "electron-updater";
import type { AppUpdaterEvents } from "electron-updater/out/AppUpdater";
type UpdateInfo = { version: string };
type Progress = { percent: number };
const t = initTRPC.create();
@@ -30,5 +35,37 @@ export const updaterRouter = t.router({
}),
check: t.procedure.query(async () => {
await autoUpdater.checkForUpdates();
})
}),
onChecking: createSubscription("checking-for-update"),
onDownloaded: createSubscription<"update-downloaded", UpdateInfo>(
"update-downloaded"
),
onDownloadProgress: createSubscription<"download-progress", Progress>(
"download-progress"
),
onNotAvailable: createSubscription<"update-not-available", UpdateInfo>(
"update-not-available"
),
onAvailable: createSubscription<"update-available", UpdateInfo>(
"update-available"
),
onError: createSubscription("error")
});
function createSubscription<
TName extends keyof AppUpdaterEvents,
TReturnType = Parameters<AppUpdaterEvents[TName]>[0]
>(eventName: TName) {
return t.procedure.subscription(() => {
return observable<TReturnType>((emit) => {
const listener: AppUpdaterEvents[TName] = (...args: any[]) => {
emit.next(args[0]);
};
autoUpdater.addListener(eventName, listener);
return () => {
autoUpdater.removeListener(eventName, listener);
};
});
});
}

View File

@@ -19,4 +19,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
export * from "./constants";
export type { AppRouter } from "./api";
export * from "./rpc";
export { type UpdateInfo } from "builder-util-runtime";

View File

@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* global MAC_APP_STORE, RELEASE */
import { client } from "./rpc/electron";
import { app, BrowserWindow, nativeTheme, shell } from "electron";
import { isDevelopment } from "./utils";
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
@@ -118,10 +117,6 @@ async function createWindow() {
nativeTheme.on("updated", () => {
setupTray();
setupJumplist();
if (getTheme() === "system") {
client.onThemeChanged(nativeTheme.shouldUseDarkColors ? "dark" : "light");
}
});
}
@@ -129,7 +124,7 @@ app.commandLine.appendSwitch("lang", "en-US");
app.on("ready", async () => {
console.info("App ready. Opening window.");
registerProtocol();
if (!isDevelopment()) registerProtocol();
await createWindow();
configureAutoUpdater();
});

View File

@@ -22,16 +22,15 @@ import { ELECTRON_TRPC_CHANNEL } from "electron-trpc/main";
import { type RendererGlobalElectronTRPC } from "electron-trpc/src/types";
import { NNCrypto } from "@notesnook/crypto";
import { ipcRenderer } from "electron";
import { CHANNEL, ITransport } from "./rpc";
declare global {
var os: string;
var electronTRPC: RendererGlobalElectronTRPC;
var RPCTransport: ITransport;
var NativeNNCrypto: new () => NNCrypto;
}
console.log("HELLO", process);
process.once("loaded", async () => {
console.log("HELLO!");
const electronTRPC: RendererGlobalElectronTRPC = {
sendMessage: (operation) =>
ipcRenderer.send(ELECTRON_TRPC_CHANNEL, operation),
@@ -39,20 +38,6 @@ process.once("loaded", async () => {
ipcRenderer.on(ELECTRON_TRPC_CHANNEL, (_event, args) => callback(args))
};
globalThis.electronTRPC = electronTRPC;
globalThis.RPCTransport = {
send(message) {
console.log("[browser] sending message", message);
ipcRenderer.send(CHANNEL, message);
},
receive(callback) {
ipcRenderer.removeAllListeners(CHANNEL);
ipcRenderer.addListener(CHANNEL, (_event, args) => {
console.log("[browser] recevied message", args);
callback(args);
});
}
};
});
globalThis.NativeNNCrypto = NNCrypto;

View File

@@ -1,37 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ipcMain } from "electron";
import { CHANNEL, createRPCClient } from ".";
import { ClientPrototype, ITransport } from "./types";
const transport: ITransport = {
send(message) {
console.log("[electron] sending message", message);
globalThis.window?.webContents.send(CHANNEL, message);
},
receive(callback) {
ipcMain.on(CHANNEL, (_event, message) => {
console.log("[electron] received message", message);
callback(message);
});
}
};
export const client = createRPCClient(transport, ClientPrototype);

View File

@@ -1,77 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ITransport } from "./types";
export const CHANNEL = "RPC_COM_CHANNEL";
type RPCApi = Record<string, (...args: any[]) => any>;
type WrappedAPI<TApi extends RPCApi> = {
[P in keyof TApi]: (
...args: Parameters<TApi[P]>
) => ReturnType<TApi[P]> extends void
? void
: ReturnType<TApi[P]> extends Promise<infer T>
? Promise<T>
: Promise<ReturnType<TApi[P]>>;
};
export function createRPCClient<TApi extends RPCApi>(
transport: ITransport,
api: TApi
): WrappedAPI<TApi> {
const wrappedAPI = <WrappedAPI<TApi>>{};
for (const method in api) {
if (Object.hasOwn(api, method)) {
wrappedAPI[<keyof TApi>method] = (...args: any[]) => {
return <any>new Promise<unknown>((resolve) => {
transport.receive((message) => {
if (message.type === "response" && message.id === method) {
resolve(message.result);
}
});
transport.send({
type: "message",
id: method,
args
});
});
};
}
}
return wrappedAPI;
}
export function createRPCServer<TApi extends RPCApi>(
transport: ITransport,
api: TApi
) {
transport.receive(async (message) => {
if (
message.type === "message" &&
message.id &&
Object.hasOwn(api, message.id)
) {
const result = await api[<keyof TApi>message.id](...message.args);
transport.send({ type: "response", id: message.id, result });
}
});
}
export * from "./types";

View File

@@ -1,55 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type {
UpdateInfo,
ProgressInfo,
UpdateDownloadedEvent
} from "electron-updater";
import type { Theme } from "../utils/theme";
export const ClientPrototype = {
onCheckingForUpdate() {},
onUpdateAvailable(info: UpdateInfo) {},
onUpdateDownloadProgress(progress: ProgressInfo) {},
onUpdateDownloadCompleted(info: UpdateDownloadedEvent) {},
onUpdateNotAvailable(info: UpdateInfo) {},
onThemeChanged(theme: Theme) {},
onNotificationClicked(tag: string) {},
onCreateItem(type: "note" | "notebook" | "reminder") {
return type;
}
};
export type IClient = typeof ClientPrototype;
export type IClientMethod = keyof IClient;
export type IMessage = {
type: "message";
id: string;
args: unknown[];
};
export type IResponse = {
type: "response";
id: string;
result: unknown;
};
export type ITransport = {
send(message: IMessage | IResponse): void;
receive(callback: (message: IMessage | IResponse) => void): void;
};

View File

@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { autoUpdater } from "electron-updater";
import { client } from "../rpc/electron";
async function configureAutoUpdater() {
autoUpdater.setFeedURL({
@@ -31,14 +30,6 @@ async function configureAutoUpdater() {
autoUpdater.allowDowngrade = false;
autoUpdater.allowPrerelease = false;
autoUpdater.autoInstallOnAppQuit = true;
autoUpdater.addListener("checking-for-update", client.onCheckingForUpdate);
autoUpdater.addListener("update-available", client.onUpdateAvailable);
autoUpdater.addListener("download-progress", client.onUpdateDownloadProgress);
autoUpdater.addListener(
"update-downloaded",
client.onUpdateDownloadCompleted
);
autoUpdater.addListener("update-not-available", client.onUpdateNotAvailable);
}
export { configureAutoUpdater };

View File

@@ -18,9 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app, Menu } from "electron";
import { client } from "../rpc/electron";
import { AssetManager } from "./asset-manager";
import { bringToFront } from "./bring-to-front";
import { bridge } from "../api/bridge";
export function setupJumplist() {
if (process.platform === "win32") {
@@ -75,7 +75,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
client.onCreateItem("note");
bridge.onCreateItem("note");
}
},
{
@@ -83,7 +83,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
client.onCreateItem("notebook");
bridge.onCreateItem("notebook");
}
},
{
@@ -91,7 +91,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
client.onCreateItem("reminder");
bridge.onCreateItem("reminder");
}
}
]);

View File

@@ -17,14 +17,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { protocol, net } from "electron";
import { protocol, ProtocolRequest } from "electron";
import { isDevelopment } from "./index";
import { createReadStream, statSync } from "fs";
import { extname, join, normalize } from "path";
import { URL } from "url";
import { Readable } from "stream";
const BASE_PATH = isDevelopment() ? "../public" : "";
const HOSTNAME = `app.notesnook.com`;
const FILE_NOT_FOUND = -6;
const SCHEME = "https";
const extensionToMimeType: Record<string, string> = {
html: "text/html",
@@ -36,36 +38,98 @@ const extensionToMimeType: Record<string, string> = {
};
function registerProtocol() {
protocol.handle(SCHEME, (request) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
console.info("Intercepting request:", request);
const protocolInterceptionResult = protocol.interceptStreamProtocol(
SCHEME,
async (request, callback) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
console.info("Intercepting request:", request.url);
const loadIndex = !extname(url.pathname);
const absoluteFilePath = normalize(
`${__dirname}${
loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
}`
);
const filePath = getPath(absoluteFilePath);
if (!filePath) {
console.error("Local asset file not found at", filePath);
return new Response(undefined, {
status: 404,
statusText: "FILE_NOT_FOUND"
const loadIndex = !extname(url.pathname);
const absoluteFilePath = normalize(
`${__dirname}${
loadIndex
? `${BASE_PATH}/index.html`
: `${BASE_PATH}/${url.pathname}`
}`
);
const filePath = getPath(absoluteFilePath);
if (!filePath) {
console.error("Local asset file not found at", filePath);
callback({ error: FILE_NOT_FOUND });
return;
}
const fileExtension = extname(filePath).replace(".", "");
const data = createReadStream(filePath);
callback({
data,
mimeType: extensionToMimeType[fileExtension]
});
} else {
let response: Response;
try {
const body = await getBody(request);
response = await fetch(request.url, {
...request,
body,
headers: {
...request.headers
// origin: `${PROTOCOL}://${HOSTNAME}/`
},
referrer: request.referrer,
redirect: "manual"
});
} catch (e) {
console.error(e);
console.error(`Error sending request to `, request.url, "Error: ", e);
callback({ statusCode: 400 });
return;
}
callback({
statusCode: response.status,
data: response.body ? Readable.fromWeb(response.body) : undefined,
headers: Object.fromEntries(response.headers.entries()),
mimeType: response.headers.get("Content-Type") || undefined
});
}
const fileExtension = extname(filePath).replace(".", "");
const data = createReadStream(filePath);
const headers = new Headers();
headers.set("Content-Type", extensionToMimeType[fileExtension]);
return new Response(data, { headers });
} else {
return net.fetch(request);
}
});
);
console.info(`${SCHEME} protocol inteception "successful"`);
console.info(
`${SCHEME} protocol inteception ${
protocolInterceptionResult ? "successful" : "failed"
}.`
);
// protocol.handle(SCHEME, (request) => {
// const url = new URL(request.url);
// if (shouldInterceptRequest(url)) {
// console.info("Intercepting request:", request.url);
// const loadIndex = !extname(url.pathname);
// const absoluteFilePath = normalize(
// `${__dirname}${
// loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
// }`
// );
// const filePath = getPath(absoluteFilePath);
// if (!filePath) {
// console.error("Local asset file not found at", filePath);
// return new Response(undefined, {
// status: 404,
// statusText: "FILE_NOT_FOUND"
// });
// }
// const fileExtension = extname(filePath).replace(".", "");
// const data = createReadStream(filePath);
// return new Response(data, {
// headers: { "Content-Type": extensionToMimeType[fileExtension] }
// });
// } else {
// return net.fetch(request);
// }
// });
// console.info(`${SCHEME} protocol inteception "successful"`);
}
const bypassedRoutes: string[] = [];
@@ -77,6 +141,24 @@ function shouldInterceptRequest(url: URL) {
const PROTOCOL_URL = `${SCHEME}://${HOSTNAME}/`;
export { registerProtocol, PROTOCOL_URL };
async function getBody(request: ProtocolRequest) {
const session = globalThis?.window?.webContents?.session;
const blobParts = [];
if (!request.uploadData || !request.uploadData.length) return null;
for (const data of request.uploadData) {
if (data.bytes) {
blobParts.push(new Uint8Array(data.bytes));
} else if (session && data.blobUUID) {
const buffer = await session.getBlobData(data.blobUUID);
if (!buffer) continue;
blobParts.push(new Uint8Array(buffer));
}
}
const blob = new Blob(blobParts);
return await blob.arrayBuffer();
}
function getPath(filePath: string): string | undefined {
try {
const result = statSync(filePath);

View File

@@ -21,7 +21,7 @@ import { app, Menu, Tray } from "electron";
import { AssetManager } from "./asset-manager";
import { isFlatpak } from "./index";
import { bringToFront } from "./bring-to-front";
import { client } from "../rpc/electron";
import { bridge } from "../api/bridge";
let tray: Tray | undefined = undefined;
export function destroyTray() {
@@ -58,7 +58,7 @@ export function setupTray() {
: AssetManager.icon("note-add", { size: trayIconSize }),
click: () => {
bringToFront();
client.onCreateItem("note");
bridge.onCreateItem("note");
}
},
{
@@ -69,7 +69,7 @@ export function setupTray() {
: AssetManager.icon("notebook-add", { size: trayIconSize }),
click: () => {
bringToFront();
client.onCreateItem("notebook");
bridge.onCreateItem("notebook");
}
},
{ type: "separator" },

View File

@@ -22,11 +22,10 @@
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.28.0",
"@tanstack/react-virtual": "^3.0.0-beta.18",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.18.0",
"@trpc/react-query": "^10.18.0",
"@trpc/client": "^10.29.1",
"@trpc/react-query": "^10.29.1",
"allotment": "^1.12.1",
"async-mutex": "^0.3.2",
"axios": "^1.3.4",
@@ -34,7 +33,7 @@
"comlink": "^4.3.1",
"cronosjs": "^1.7.1",
"dayjs": "^1.10.4",
"electron-trpc": "^0.4.2",
"electron-trpc": "^0.5.0",
"event-source-polyfill": "^1.0.25",
"fflate": "^0.7.4",
"file-saver": "^2.0.5",
@@ -68,6 +67,7 @@
},
"devDependencies": {
"@playwright/test": "^1.26.0",
"@trpc/server": "^10.29.1",
"@types/file-saver": "^2.0.5",
"@types/hookrouter": "^2.2.5",
"@types/marked": "^4.0.7",
@@ -81,6 +81,7 @@
"buffer": "^6.0.3",
"chalk": "^4.1.0",
"dotenv": "^10.0.0",
"electron-updater": "^5.3.0",
"env-cmd": "^10.1.0",
"file-loader": "^6.2.0",
"find-process": "^1.4.4",
@@ -4699,28 +4700,6 @@
}
}
},
"node_modules/@tanstack/react-virtual": {
"version": "3.0.0-beta.48",
"license": "MIT",
"dependencies": {
"@tanstack/virtual-core": "3.0.0-beta.48"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@tanstack/virtual-core": {
"version": "3.0.0-beta.48",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@theme-ui/components": {
"version": "0.14.7",
"license": "MIT",
@@ -4778,23 +4757,40 @@
}
},
"node_modules/@trpc/client": {
"version": "10.18.0",
"license": "MIT",
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.29.1.tgz",
"integrity": "sha512-+9Tifg6dtKsYLsqOW0wizqc3iILAkXxn16pyYAeMDPlulPEqNvnI85GDJ0zJOJLIkQnQefkRbtCmtDxLNtV9Eg==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@trpc/server": "10.18.0"
"@trpc/server": "10.29.1"
}
},
"node_modules/@trpc/react-query": {
"version": "10.18.0",
"license": "MIT",
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.29.1.tgz",
"integrity": "sha512-yWsce8euPSVtn3SeBKXxLmq607/sqyIez7pgMOhMBKehRNdZzrGp3MhjmRwim+IUKLrw71kUgsw7w6uT5FPB0g==",
"funding": [
"https://trpc.io/sponsor"
],
"peerDependencies": {
"@tanstack/react-query": "^4.18.0",
"@trpc/client": "10.18.0",
"@trpc/server": "10.18.0",
"@trpc/client": "10.29.1",
"@trpc/server": "10.29.1",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@trpc/server": {
"version": "10.29.1",
"resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.29.1.tgz",
"integrity": "sha512-kNXgMh5ya+awuz2tB4eIyVrRs7nVtqGXwSGabzH3l5ZLWz7rbKJquOJ7h6bjvIfWUpaFG62HJNWxxGUtXCRgRw==",
"dev": true,
"funding": [
"https://trpc.io/sponsor"
]
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"license": "ISC",
@@ -6517,6 +6513,19 @@
"version": "1.1.2",
"license": "MIT"
},
"node_modules/builder-util-runtime": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.1.1.tgz",
"integrity": "sha512-azRhYLEoDvRDR8Dhis4JatELC/jUvYjm4cVSj7n9dauGTOM2eeNn9KS0z6YA6oDsjI1xphjNbY6PZZeHPzzqaw==",
"dev": true,
"dependencies": {
"debug": "^4.3.4",
"sax": "^1.2.4"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/builtin-modules": {
"version": "3.3.0",
"license": "MIT",
@@ -7985,14 +7994,67 @@
"license": "ISC"
},
"node_modules/electron-trpc": {
"version": "0.4.2",
"license": "MIT",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.5.0.tgz",
"integrity": "sha512-xvnvOpuI0IiecMGS9VOS5/3kLj6IUpjngKhv5VqXU9vP2LzE140G8gqaziX0Tl7MaiYmJZbad/imis9i49n/4A==",
"dependencies": {
"debug": "^4.3.4"
},
"peerDependencies": {
"@trpc/client": ">10.0.0",
"@trpc/server": ">10.0.0",
"electron": ">19.0.0"
}
},
"node_modules/electron-updater": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.3.0.tgz",
"integrity": "sha512-iKEr7yQBcvnQUPnSDYGSWC9t0eF2YbZWeYYYZzYxdl+HiRejXFENjYMnYjoOm2zxyD6Cr2JTHZhp9pqxiXuCOw==",
"dev": true,
"dependencies": {
"@types/semver": "^7.3.6",
"builder-util-runtime": "9.1.1",
"fs-extra": "^10.0.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
"lodash.escaperegexp": "^4.1.2",
"lodash.isequal": "^4.5.0",
"semver": "^7.3.5",
"typed-emitter": "^2.1.0"
}
},
"node_modules/electron-updater/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/electron-updater/node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/electron-updater/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/emittery": {
"version": "0.8.1",
"license": "MIT",
@@ -11920,6 +11982,12 @@
"language-subtag-registry": "~0.3.2"
}
},
"node_modules/lazy-val": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
"integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==",
"dev": true
},
"node_modules/leven": {
"version": "3.1.0",
"license": "MIT",
@@ -12042,6 +12110,12 @@
"version": "4.0.8",
"license": "MIT"
},
"node_modules/lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
"integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
"dev": true
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"license": "MIT"
@@ -15534,6 +15608,23 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"optional": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/rxjs/node_modules/tslib": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==",
"dev": true,
"optional": true
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"funding": [
@@ -17040,6 +17131,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typed-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
"integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
"dev": true,
"optionalDependencies": {
"rxjs": "*"
}
},
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
"license": "MIT",

View File

@@ -30,11 +30,10 @@
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.28.0",
"@tanstack/react-virtual": "^3.0.0-beta.18",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.18.0",
"@trpc/react-query": "^10.18.0",
"@trpc/client": "^10.29.1",
"@trpc/react-query": "^10.29.1",
"allotment": "^1.12.1",
"async-mutex": "^0.3.2",
"axios": "^1.3.4",
@@ -42,7 +41,7 @@
"comlink": "^4.3.1",
"cronosjs": "^1.7.1",
"dayjs": "^1.10.4",
"electron-trpc": "^0.4.2",
"electron-trpc": "^0.5.0",
"event-source-polyfill": "^1.0.25",
"fflate": "^0.7.4",
"file-saver": "^2.0.5",
@@ -75,6 +74,7 @@
"zustand": "^3.3.1"
},
"devDependencies": {
"@trpc/server": "^10.29.1",
"@playwright/test": "^1.26.0",
"@types/file-saver": "^2.0.5",
"@types/hookrouter": "^2.2.5",

View File

@@ -30,7 +30,6 @@ import { introduceFeatures, showUpgradeReminderDialogs } from "./common";
import { AppEventManager, AppEvents } from "./common/app-events";
import { db } from "./common/db";
import { EV, EVENTS } from "@notesnook/core/common";
import { EVENTS as DESKTOP_APP_EVENTS } from "@notesnook/desktop";
import { registerKeyMap } from "./common/key-map";
import { isUserPremium } from "./hooks/use-is-user-premium";
import {
@@ -46,6 +45,7 @@ import { updateStatus, removeStatus, getStatus } from "./hooks/use-status";
import { showToast } from "./utils/toast";
import { interruptedOnboarding } from "./components/dialogs/onboarding-dialog";
import { hashNavigate } from "./navigation";
import { desktop } from "./common/desktop-bridge";
export default function AppEffects({ setShow }) {
const refreshNavItems = useStore((store) => store.refreshNavItems);
@@ -198,19 +198,26 @@ export default function AppEffects({ setShow }) {
}, [isSystemThemeDark, followSystemTheme, setTheme]);
useEffect(() => {
AppEventManager.subscribe(DESKTOP_APP_EVENTS.createItem, ({ itemType }) => {
switch (itemType) {
case "note":
hashNavigate("/notes/create", { addNonce: true, replace: true });
break;
case "notebook":
hashNavigate("/notebooks/create", { replace: true });
break;
case "reminder":
hashNavigate("/reminders/create", { replace: true });
break;
}
});
const { unsubscribe } =
desktop?.bridge.onCreateItem.subscribe(undefined, {
onData(itemType) {
switch (itemType) {
case "note":
hashNavigate("/notes/create", { addNonce: true, replace: true });
break;
case "notebook":
hashNavigate("/notebooks/create", { replace: true });
break;
case "reminder":
hashNavigate("/reminders/create", { replace: true });
break;
}
}
}) || {};
return () => {
unsubscribe();
};
}, []);
return <React.Fragment />;

View File

@@ -1,38 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { AppEventManager } from "../common/app-events";
import { isDesktop } from "../utils/platform";
export function invokeCommand(type, payload = {}) {
if (!isDesktop()) return;
// window.api.send("fromRenderer", {
// type,
// ...payload
// });
}
// if (isDesktop()) {
// window.api.receive("fromMain", (args) => {
// console.log(args);
// const { type, ...other } = args;
// AppEventManager.publish(type, other);
// });
// }

View File

@@ -1,40 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/desktop";
import { AppEventManager } from "../common/app-events";
import { invokeCommand } from "./index";
/**
*
* @param {import("electron").NotificationConstructorOptions & { tag: string }} options
* @param {() => void} onClicked
*/
export default function showNotification(options, onClicked) {
invokeCommand("showNotification", options);
const { unsubscribe } = AppEventManager.subscribe(
EVENTS.notificationClicked,
({ tag }) => {
if (tag === options.tag) {
onClicked();
unsubscribe();
}
}
);
}

View File

@@ -23,5 +23,15 @@ export const AppEventManager = new EventManager();
export const AppEvents = {
UPDATE_ATTACHMENT_PROGRESS: "updateAttachmentProgress",
UPDATE_STATUS: "updateStatus",
REMOVE_STATUS: "removeStatus"
REMOVE_STATUS: "removeStatus",
checkingForUpdate: "checkingForUpdate",
updateAvailable: "updateAvailable",
updateDownloadProgress: "updateDownloadProgress",
updateDownloadCompleted: "updateDownloadCompleted",
updateNotAvailable: "updateNotAvailable",
updateError: "updateError",
themeChanged: "themeChanged",
notificationClicked: "notificationClicked",
createItem: "createItem"
};

View File

@@ -19,31 +19,47 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { createTRPCProxyClient } from "@trpc/client";
import { ipcLink } from "electron-trpc/renderer";
import { AppRouter, createRPCServer, IClient } from "@notesnook/desktop";
import "@notesnook/desktop/dist/rpc/browser";
import type { AppRouter } from "@notesnook/desktop";
import { AppEventManager, AppEvents } from "../app-events";
export const desktop = createTRPCProxyClient<AppRouter>({
links: [ipcLink()]
});
const client: IClient = {
onCheckingForUpdate: function (): void {
throw new Error("Function not implemented.");
},
onUpdateAvailable() {},
onUpdateDownloadProgress() {},
onUpdateDownloadCompleted() {},
onUpdateNotAvailable() {},
onThemeChanged: function (theme: "system" | "light" | "dark"): void {
throw new Error("Function not implemented.");
},
onNotificationClicked: function (tag: string): void {
throw new Error("Function not implemented.");
},
onCreateItem: function (type: "note" | "notebook" | "reminder") {
console.log("GOT", type);
return type;
}
};
desktop.updater.onChecking.subscribe(
undefined,
attachListener(AppEvents.checkingForUpdate)
);
createRPCServer(window.RPCTransport, client);
desktop.updater.onAvailable.subscribe(
undefined,
attachListener(AppEvents.updateAvailable)
);
desktop.updater.onDownloaded.subscribe(
undefined,
attachListener(AppEvents.updateDownloadCompleted)
);
desktop.updater.onDownloadProgress.subscribe(
undefined,
attachListener(AppEvents.updateDownloadProgress)
);
desktop.updater.onNotAvailable.subscribe(
undefined,
attachListener(AppEvents.updateNotAvailable)
);
desktop.updater.onError.subscribe(
undefined,
attachListener(AppEvents.updateError)
);
function attachListener(event: string) {
return {
onData(...args: any[]) {
AppEventManager.publish(event, ...args);
}
};
}

View File

@@ -16,10 +16,10 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-var */
import { ITransport } from "./types";
import { type desktop as bridge } from "./bridge";
declare global {
var RPCTransport: ITransport;
}
export const desktop: typeof bridge | undefined =
process.env.REACT_APP_PLATFORM === "desktop"
? require("./bridge").desktop
: undefined;

View File

@@ -38,6 +38,7 @@ import { PATHS } from "@notesnook/desktop";
import { TaskManager } from "./task-manager";
import { EVENTS } from "@notesnook/core/common";
import { getFormattedDate } from "../utils/time";
import { desktop } from "./desktop-bridge";
export const CREATE_BUTTON_MAP = {
notes: {
@@ -103,7 +104,7 @@ export async function createBackup() {
PATHS.backupsDirectory
);
const filePath = `${directory}/${filename}.${ext}`;
saveFile(filePath, data);
await desktop?.integration.saveFile.query(filePath, data);
showToast("success", `Backup saved at ${filePath}.`);
} else {
FileSaver.saveAs(new Blob([Buffer.from(data)]), `${filename}.${ext}`);

View File

@@ -18,21 +18,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useEffect, useState } from "react";
import { AppEventManager } from "../common/app-events";
import { EVENTS } from "@notesnook/desktop";
import {
showUpdateAvailableNotice,
showUpdateReadyNotice
} from "../common/dialog-controller";
import { isDesktop } from "../utils/platform";
import { checkForUpdate } from "../utils/updater";
import { AppEventManager, AppEvents } from "../common/app-events";
var checkingForUpdateTimeout = 0;
type CompletedUpdateStatus = { type: "completed"; version: string };
type DownloadingUpdateStatus = { type: "downloading"; progress: number };
type AvailableUpdateStatus = { type: "available"; version: string };
type GenericUpdateStatus = { type: "checking" | "updated" };
type UpdateStatus =
| AvailableUpdateStatus
| CompletedUpdateStatus
| DownloadingUpdateStatus
| GenericUpdateStatus;
let checkingForUpdateTimeout = 0;
export function useAutoUpdater() {
const [status, setStatus] = useState();
const [status, setStatus] = useState<UpdateStatus>();
useEffect(() => {
function changeStatus(status) {
function changeStatus(status?: UpdateStatus) {
clearTimeout(checkingForUpdateTimeout);
setStatus(status);
}
@@ -41,10 +50,10 @@ export function useAutoUpdater() {
changeStatus({ type: "checking" });
checkingForUpdateTimeout = setTimeout(() => {
changeStatus({ type: "updated" });
}, 10000);
}, 10000) as unknown as number;
}
function updateAvailable(info) {
function updateAvailable(info: { version: string }) {
changeStatus({
type: "available",
version: info.version
@@ -59,33 +68,33 @@ export function useAutoUpdater() {
else changeStatus();
}
function updateDownloadCompleted(info) {
function updateDownloadCompleted(info: { version: string }) {
changeStatus({ type: "completed", version: info.version });
showUpdateReadyNotice({ version: info.version });
}
function updateDownloadProgress(progressInfo) {
function updateDownloadProgress(progressInfo: { percent: number }) {
changeStatus({ type: "downloading", progress: progressInfo.percent });
}
const checkingForUpdateEvent = AppEventManager.subscribe(
EVENTS.checkingForUpdate,
AppEvents.checkingForUpdate,
checkingForUpdate
);
const updateAvailableEvent = AppEventManager.subscribe(
EVENTS.updateAvailable,
AppEvents.updateAvailable,
updateAvailable
);
const updateNotAvailableEvent = AppEventManager.subscribe(
EVENTS.updateNotAvailable,
AppEvents.updateNotAvailable,
updateNotAvailable
);
const updateCompletedEvent = AppEventManager.subscribe(
EVENTS.updateDownloadCompleted,
AppEvents.updateDownloadCompleted,
updateDownloadCompleted
);
const updateProgressEvent = AppEventManager.subscribe(
EVENTS.updateDownloadProgress,
AppEvents.updateDownloadProgress,
updateDownloadProgress
);

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useCallback, useEffect, useState } from "react";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
export type DesktopIntegrationSettings = {
autoStart: boolean;
@@ -31,7 +31,7 @@ export default function useDesktopIntegration() {
const [settings, changeSettings] = useState<DesktopIntegrationSettings>();
const setupDesktopIntegration = useCallback(async () => {
const settings = await desktop.integration.desktopIntegration.query();
const settings = await desktop?.integration.desktopIntegration.query();
changeSettings(settings);
return settings;
}, []);
@@ -46,7 +46,7 @@ export default function useDesktopIntegration() {
async (_settings: Partial<DesktopIntegrationSettings>) => {
if (!settings) return;
await desktop.integration.setDesktopIntegration.mutate({
await desktop?.integration.setDesktopIntegration.mutate({
...settings,
..._settings
});

View File

@@ -18,19 +18,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useCallback, useEffect, useState } from "react";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
export default function usePrivacyMode() {
const [privacyMode, setPrivacyMode] = useState(false);
useEffect(() => {
(async function () {
setPrivacyMode(await desktop.integration.privacyMode.query());
setPrivacyMode((await desktop?.integration.privacyMode.query()) || false);
})();
}, []);
const set = useCallback(async (privacyMode) => {
await desktop.integration.setPrivacyMode.mutate(privacyMode);
await desktop?.integration.setPrivacyMode.mutate(privacyMode);
setPrivacyMode(privacyMode);
}, []);

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useCallback, useEffect, useState } from "react";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
export type Language = { code: string; name: string };
export type SpellCheckerOptions = {
@@ -32,9 +32,10 @@ export default function useSpellChecker() {
const loadSpellChecker = useCallback(async () => {
setSpellChecker({
enabledLanguages: await desktop.spellChecker.enabledLanguages.query(),
languages: await desktop.spellChecker.languages.query(),
enabled: await desktop.spellChecker.isEnabled.query()
enabledLanguages:
(await desktop?.spellChecker.enabledLanguages.query()) || [],
languages: (await desktop?.spellChecker.languages.query()) || [],
enabled: (await desktop?.spellChecker.isEnabled.query()) || false
});
}, []);
@@ -46,7 +47,7 @@ export default function useSpellChecker() {
const toggle = useCallback(
async (enabled: boolean) => {
await desktop.spellChecker.toggle.mutate(enabled);
await desktop?.spellChecker.toggle.mutate(enabled);
await loadSpellChecker();
},
[loadSpellChecker]
@@ -54,7 +55,7 @@ export default function useSpellChecker() {
const setLanguages = useCallback(
async (languages: string[]) => {
await desktop.spellChecker.setLanguages.mutate(languages);
await desktop?.spellChecker.setLanguages.mutate(languages);
await loadSpellChecker();
},
[loadSpellChecker]

View File

@@ -17,10 +17,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/desktop";
import { useEffect, useState } from "react";
import { AppEventManager } from "../common/app-events";
import useMediaQuery from "./use-media-query";
import { desktop } from "../common/desktop-bridge";
function useSystemTheme() {
const isDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
@@ -31,12 +30,12 @@ function useSystemTheme() {
}, [isDarkMode]);
useEffect(() => {
function onThemeChanged({ theme }) {
setSystemTheme(theme);
}
AppEventManager.subscribe(EVENTS.themeChanged, onThemeChanged);
const { unsubscribe } =
desktop?.integration.onThemeChanged.subscribe(undefined, {
onData: setSystemTheme
}) || {};
return () => {
AppEventManager.unsubscribe(EVENTS.themeChanged, onThemeChanged);
unsubscribe?.();
};
}, []);

View File

@@ -18,19 +18,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useCallback, useEffect, useState } from "react";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
export default function useZoomFactor() {
const [zoom, setZoom] = useState(1.0);
useEffect(() => {
(async function () {
setZoom(await desktop.integration.zoomFactor.query());
setZoom((await desktop?.integration.zoomFactor.query()) || 1.0);
})();
}, []);
const set = useCallback(async (zoomFactor) => {
await desktop.integration.setZoomFactor.mutate(zoomFactor);
await desktop?.integration.setZoomFactor.mutate(zoomFactor);
setZoom(zoomFactor);
}, []);

View File

@@ -18,8 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import "@notesnook/core/types";
import { EVENTS } from "@notesnook/desktop";
import { AppEventManager } from "./common/app-events";
import { AppEventManager, AppEvents } from "./common/app-events";
import { render } from "react-dom";
import { getCurrentHash, getCurrentPath, makeURL } from "./navigation";
import Config from "./utils/config";
@@ -30,7 +29,6 @@ import { AuthProps } from "./views/auth";
global.Buffer = Buffer;
initalizeLogger();
if (process.env.REACT_APP_PLATFORM === "desktop") require("./commands");
type Route<TProps = null> = {
component: () => Promise<{
@@ -188,7 +186,7 @@ async function initializeServiceWorker() {
const { formatted } = await getServiceWorkerVersion(
registration.waiting
);
AppEventManager.publish(EVENTS.updateDownloadCompleted, {
AppEventManager.publish(AppEvents.updateDownloadCompleted, {
version: formatted
});
}

View File

@@ -27,7 +27,7 @@ import dayjs from "dayjs";
import Config from "../utils/config";
import { store as notestore } from "./note-store";
import { isDesktop, isTesting } from "../utils/platform";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
class ReminderStore extends BaseStore {
reminders = [];
@@ -99,26 +99,25 @@ function scheduleReminder(id, reminder, cron) {
}
if (isDesktop()) {
await desktop.integration.showNotification.query(
{
title: reminder.title,
body: reminder.description,
silent: reminder.priority === "silent",
timeoutType: reminder.priority === "urgent" ? "never" : "default",
urgency:
reminder.priority === "urgent"
? "critical"
: reminder.priority === "vibrate"
? "normal"
: "low",
focusOnClick: true,
tag: id
},
async () => {
await desktop.integration.bringToFront.query();
showReminderPreviewDialog(reminder);
}
);
const tag = await desktop?.integration.showNotification.query({
title: reminder.title,
body: reminder.description,
silent: reminder.priority === "silent",
timeoutType: reminder.priority === "urgent" ? "never" : "default",
urgency:
reminder.priority === "urgent"
? "critical"
: reminder.priority === "vibrate"
? "normal"
: "low",
focusOnClick: true,
tag: id
});
if (tag) {
await desktop?.integration.bringToFront.query();
showReminderPreviewDialog(reminder);
}
} else {
const notification = new Notification(reminder.title, {
body: reminder.description,

View File

@@ -23,7 +23,7 @@ import Worker from "worker-loader?filename=static/workers/compressor.worker.[con
import type { Compressor as CompressorWorker } from "./compressor.worker";
import { wrap, Remote } from "comlink";
import { isDesktop } from "./platform";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
export class Compressor {
private worker!: globalThis.Worker;
@@ -38,13 +38,13 @@ export class Compressor {
async compress(data: string) {
if (isDesktop())
return await desktop.compress.gzip.query({ data, level: 6 });
return await desktop?.compress.gzip.query({ data, level: 6 });
return await this.compressor.gzip({ data, level: 6 });
}
async decompress(data: string) {
if (isDesktop()) return await desktop.compress.gunzip.query(data);
if (isDesktop()) return await desktop?.compress.gunzip.query(data);
return await this.compressor.gunzip({ data });
}

View File

@@ -17,16 +17,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EVENTS } from "@notesnook/desktop";
import { AppEventManager } from "../common/app-events";
import { desktop } from "../common/desktop-client";
import { AppEventManager, AppEvents } from "../common/app-events";
import { desktop } from "../common/desktop-bridge";
import { isDesktop } from "./platform";
import { appVersion, getServiceWorkerVersion } from "./version";
export async function checkForUpdate() {
if (isDesktop()) await desktop.updater.check.query();
if (isDesktop()) await desktop?.updater.check.query();
else {
AppEventManager.publish(EVENTS.checkingForUpdate);
AppEventManager.publish(AppEvents.checkingForUpdate);
const registrations =
(await navigator.serviceWorker?.getRegistrations()) || [];
@@ -41,19 +40,19 @@ export async function checkForUpdate() {
continue;
}
AppEventManager.publish(EVENTS.updateDownloadCompleted, {
AppEventManager.publish(AppEvents.updateDownloadCompleted, {
version: workerVersion.formatted
});
return;
}
}
AppEventManager.publish(EVENTS.updateNotAvailable);
AppEventManager.publish(AppEvents.updateNotAvailable);
}
}
export async function downloadUpdate() {
if (isDesktop()) await desktop.updater.download.query();
if (isDesktop()) await desktop?.updater.download.query();
else {
console.log("Force updating");
if (!("serviceWorker" in navigator)) return;
@@ -63,7 +62,7 @@ export async function downloadUpdate() {
}
export async function installUpdate() {
if (isDesktop()) await desktop.updater.install.query();
if (isDesktop()) await desktop?.updater.install.query();
else {
const registrations =
(await navigator.serviceWorker?.getRegistrations()) || [];

View File

@@ -87,7 +87,7 @@ import { writeText } from "clipboard-polyfill";
import { useEditorConfig } from "../components/editor/context";
import { getFonts } from "@notesnook/editor";
import { formatDate } from "@notesnook/core/utils/date";
import { desktop } from "../common/desktop-client";
import { desktop } from "../common/desktop-bridge";
function subscriptionStatusToString(user) {
const status = user?.subscription?.type;
@@ -938,7 +938,7 @@ function Settings() {
variant="list"
onClick={async () => {
const location =
await desktop.integration.selectDirectory.query({
await desktop?.integration.selectDirectory.query({
title: "Select where Notesnook should save backups",
defaultPath:
backupStorageLocation || PATHS.backupsDirectory
@@ -1156,7 +1156,7 @@ function Settings() {
<Button
variant="list"
onClick={async () => {
await desktop.integration.openPath.query({
await desktop?.integration.openPath.query({
type: "path",
link: PATHS.logsDirectory
});

1308
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,9 @@
"nx": "^15.7.2",
"patch-package": "^6.5.0",
"prettier": "^2.7.1",
"serve": "^14.0.1"
"serve": "^14.0.1",
"turbowatch": "^2.29.4",
"zx": "^7.2.2"
},
"dependencies": {
"@nrwl/nx-cloud": "^14.6.2",

View File

@@ -63,7 +63,6 @@
"prosemirror-test-builder": "^1.1.0",
"vitest": "^0.29.2",
"web-vitals": "^2.1.4",
"zx": "^7.0.8",
"react": "17.0.2",
"react-dom": "17.0.2"
},