From abbc1ad628a901fb5b27d7db124a2fbdb5f86e17 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 30 Apr 2026 18:09:35 +0800 Subject: [PATCH] Merge pull request #12548 from logseq/feat/desktop-bundle-cli Feat/desktop bundle cli --- .github/workflows/build-desktop-release.yml | 18 +- gulpfile.js | 21 +- package.json | 9 +- resources/package.json | 22 +- resources/pnpm-lock.yaml | 431 +++++++++++++++++++ scripts/build-db-worker-node-bundle.mjs | 21 +- scripts/prepare-desktop-runtime-js.mjs | 65 +++ src/electron/electron/core.cljs | 116 +++++ src/main/frontend/worker/platform/node.cljs | 4 +- src/main/logseq/cli/command/doctor.cljs | 2 +- src/main/logseq/cli/server.cljs | 6 +- src/test/logseq/cli/command/doctor_test.cljs | 6 +- 12 files changed, 697 insertions(+), 24 deletions(-) create mode 100644 scripts/prepare-desktop-runtime-js.mjs diff --git a/.github/workflows/build-desktop-release.yml b/.github/workflows/build-desktop-release.yml index 251c248a13..ccd92e5531 100644 --- a/.github/workflows/build-desktop-release.yml +++ b/.github/workflows/build-desktop-release.yml @@ -135,11 +135,27 @@ jobs: echo "ENABLE_FILE_SYNC_PRODUCTION=${{ github.event_name == 'schedule' || github.event.inputs.enable-file-sync-production == 'true' }}" >> $GITHUB_ENV - name: Compile CLJS - run: pnpm install --frozen-lockfile && gulp build && pnpm cljs:release-electron && pnpm webpack-app-build + run: pnpm install --frozen-lockfile && gulp build && pnpm cljs:release-electron && pnpm db-worker-node:bundle && pnpm webpack-app-build && pnpm desktop:prepare-runtime-js env: LOGSEQ_SENTRY_DSN: ${{ secrets.LOGSEQ_SENTRY_DSN }} LOGSEQ_POSTHOG_TOKEN: ${{ secrets.LOGSEQ_POSTHOG_TOKEN }} + - name: Verify bundled db-worker-node runtime + run: | + test -f ./dist/db-worker-node.js + test -f ./dist/db-worker-node-assets.json + + - name: Verify bundled CLI + run: | + test -f ./static/js/logseq-cli.js + node ./static/js/logseq-cli.js --help >/tmp/logseq-cli-help.txt + grep -E "USAGE|Usage|COMMANDS|Commands" /tmp/logseq-cli-help.txt >/dev/null + + - name: Verify desktop runtime script locations + run: | + test -f ./static/js/db-worker-node.js + test -f ./static/js/logseq-cli.js + - name: Update APP Version run: | sed -i 's/"version": "0.0.1"/"version": "${{ steps.ref.outputs.version }}"/g' ./package.json diff --git a/gulpfile.js b/gulpfile.js index 7f31d5efc4..3619962289 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,10 @@ const mobilePath = path.join(outputPath, 'mobile') const mobileJsPath = path.join(mobilePath, 'js') const sourcePath = path.join(__dirname, 'src/main/frontend') const resourceFilePath = path.join(resourcesPath, '**') +const resourceSyncGlobs = [ + resourceFilePath, + '!' + path.join(resourcesPath, 'node_modules/**'), +] const outputFilePath = path.join(outputPath, '**') const rawCopySrc = (globs, options = {}) => gulp.src(globs, { encoding: false, ...options }) @@ -77,7 +81,7 @@ const common = { }, syncResourceFile () { - return rawCopySrc(resourceFilePath).pipe(gulp.dest(outputPath)) + return rawCopySrc(resourceSyncGlobs).pipe(gulp.dest(outputPath)) }, // NOTE: All assets from node_modules are copied to the output directory @@ -156,7 +160,7 @@ const common = { }, keepSyncResourceFile () { - return gulp.watch(resourceFilePath, { ignoreInitial: true }, + return gulp.watch(resourceSyncGlobs, { ignoreInitial: true }, common.syncResourceFile) }, @@ -256,12 +260,10 @@ const common = { } exports.electron = () => { - if (!fs.existsSync(path.join(outputPath, 'node_modules'))) { - cp.execSync('pnpm install --frozen-lockfile', { - cwd: outputPath, - stdio: 'inherit', - }) - } + cp.execSync('pnpm install --frozen-lockfile', { + cwd: outputPath, + stdio: 'inherit', + }) cp.execSync('pnpm electron:dev', { cwd: outputPath, @@ -273,6 +275,9 @@ exports.electronMaker = async () => { cp.execSync('pnpm cljs:release-electron', { stdio: 'inherit', }) + cp.execSync('pnpm desktop:prepare-runtime-js', { + stdio: 'inherit', + }) const pkgPath = path.join(outputPath, 'package.json') const pkg = require(pkgPath) diff --git a/package.json b/package.json index 12afaa78c3..1c518b6533 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "cljs:app-watch": "clojure -M:cljs watch app db-worker db-worker-node logseq-cli", "cljs:electron-watch": "clojure -M:cljs watch app db-worker db-worker-node electron logseq-cli test --config-merge \"{:asset-path \\\"./js\\\"}\"", "cljs:release": "clojure -M:cljs release app db-worker db-worker-node publishing electron", - "cljs:release-electron": "clojure -M:cljs release app db-worker db-worker-node electron --debug && clojure -M:cljs release publishing", + "cljs:release-electron": "clojure -M:cljs release app db-worker db-worker-node electron logseq-cli publishing", "cljs:release-app": "clojure -M:cljs release app db-worker db-worker-node", "cljs:release-publishing": "clojure -M:cljs release app publishing", "cljs:test": "clojure -M:test compile test", @@ -104,13 +104,14 @@ "db-worker-node:bundle": "node ./scripts/build-db-worker-node-bundle.mjs", "db-worker-node:release:bundle": "run-s db-worker-node:release db-worker-node:bundle", "db-worker-node:compile:bundle": "run-s db-worker-node:compile db-worker-node:bundle", + "desktop:prepare-runtime-js": "node ./scripts/prepare-desktop-runtime-js.mjs", "cli:e2e": "bb dev:cli-e2e", "cli:e2e:skip-build": "bb dev:cli-e2e --skip-build", "cljs:dev-release-app": "clojure -M:cljs release app db-worker db-worker-node --config-merge \"{:closure-defines {frontend.config/DEV-RELEASE true}}\"", - "cljs:dev-release-electron": "clojure -M:cljs release app db-worker db-worker-node electron --debug --config-merge \"{:closure-defines {frontend.config/DEV-RELEASE true}}\" && clojure -M:cljs release publishing", + "cljs:dev-release-electron": "clojure -M:cljs release app db-worker db-worker-node electron logseq-cli --debug --config-merge \"{:closure-defines {frontend.config/DEV-RELEASE true}}\" && clojure -M:cljs release publishing", "cljs:debug": "clojure -M:cljs release app db-worker db-worker-node --debug", "cljs:report": "clojure -M:cljs run shadow.cljs.build-report app db-worker db-worker-node report.html", - "cljs:build-electron": "clojure -A:cljs compile app db-worker db-worker-node electron", + "cljs:build-electron": "clojure -A:cljs compile app db-worker db-worker-node electron logseq-cli", "cljs:lint": "clojure -M:clj-kondo --parallel --lint src --cache false", "ios:dev": "cross-env PLATFORM=ios gulp cap", "android:dev": "cross-env PLATFORM=android gulp cap", @@ -192,7 +193,7 @@ "string-width": "8.2.0", "url": "^0.11.4", "util": "^0.12.5", - "keytar": "^7.9.0" + "keytar": "^7.9.0" }, "pnpm": { "overrides": { diff --git a/resources/package.json b/resources/package.json index 6a32f0c0aa..0a0fe74196 100644 --- a/resources/package.json +++ b/resources/package.json @@ -21,24 +21,33 @@ }, "dependencies": { "@fastify/cors": "11.2.0", + "@js-joda/core": "3.2.0", "@modelcontextprotocol/sdk": "^1.27.1", "abort-controller": "3.0.0", "command-exists": "1.2.9", "diff-match-patch": "1.0.5", "electron-dl": "4.0.0", "electron-log": "5.4.3", + "electron-updater": "6.8.3", "electron-window-state": "5.0.3", "extract-zip": "2.0.1", "fastify": "5.8.2", "fs-extra": "^11.3.4", + "fuse.js": "7.1.0", "https-proxy-agent": "8.0.0", + "keytar": "^7.9.0", + "mldoc": "^1.5.9", "node-fetch": "3.3.2", "open": "11.0.0", + "picocolors": "1.1.1", + "remove-accents": "0.5.0", + "sanitize-filename": "1.6.4", "semver": "7.7.4", "socks-proxy-agent": "9.0.0", - "electron-updater": "6.8.3", - "zod": "^4.3.6", - "keytar": "^7.9.0" + "string-width": "8.2.0", + "tiny-pinyin": "1.3.2", + "ws": "^8.20.0", + "zod": "^4.3.6" }, "devDependencies": { "electron": "39.8.8", @@ -47,5 +56,12 @@ }, "resolutions": { "node-abi": "4.28.0" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "electron", + "electron-winstaller", + "keytar" + ] } } diff --git a/resources/pnpm-lock.yaml b/resources/pnpm-lock.yaml index 0fd7208f79..3adc1946a0 100644 --- a/resources/pnpm-lock.yaml +++ b/resources/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@fastify/cors': specifier: 11.2.0 version: 11.2.0 + '@js-joda/core': + specifier: 3.2.0 + version: 3.2.0 '@modelcontextprotocol/sdk': specifier: ^1.27.1 version: 1.29.0(zod@4.3.6) @@ -47,24 +50,48 @@ importers: fs-extra: specifier: ^11.3.4 version: 11.3.4 + fuse.js: + specifier: 7.1.0 + version: 7.1.0 https-proxy-agent: specifier: 8.0.0 version: 8.0.0 keytar: specifier: ^7.9.0 version: 7.9.0 + mldoc: + specifier: ^1.5.9 + version: 1.5.9 node-fetch: specifier: 3.3.2 version: 3.3.2 open: specifier: 11.0.0 version: 11.0.0 + picocolors: + specifier: 1.1.1 + version: 1.1.1 + remove-accents: + specifier: 0.5.0 + version: 0.5.0 + sanitize-filename: + specifier: 1.6.4 + version: 1.6.4 semver: specifier: 7.7.4 version: 7.7.4 socks-proxy-agent: specifier: 9.0.0 version: 9.0.0 + string-width: + specifier: 8.2.0 + version: 8.2.0 + tiny-pinyin: + specifier: 1.3.2 + version: 1.3.2 + ws: + specifier: ^8.20.0 + version: 8.20.0 zod: specifier: ^4.3.6 version: 4.3.6 @@ -163,6 +190,9 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + '@js-joda/core@3.2.0': + resolution: {integrity: sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==} + '@malept/cross-spawn-promise@2.0.0': resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} engines: {node: '>= 12.13.0'} @@ -290,6 +320,14 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@3.0.1: + resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} + engines: {node: '>=4'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -423,6 +461,10 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -457,6 +499,9 @@ packages: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} + cliui@4.1.0: + resolution: {integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -468,6 +513,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -533,6 +582,10 @@ packages: cross-dirname@0.1.0: resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} + cross-spawn@6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} + engines: {node: '>=4.8'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -550,6 +603,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -757,6 +814,10 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} + execa@1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -845,6 +906,10 @@ packages: resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} engines: {node: '>=20'} + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -898,10 +963,21 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + + get-caller-file@1.0.3: + resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -910,6 +986,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -1028,6 +1108,10 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + invert-kv@2.0.0: + resolution: {integrity: sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==} + engines: {node: '>=4'} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -1045,6 +1129,14 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -1069,6 +1161,10 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-stream@1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -1155,12 +1251,20 @@ packages: lazy-val@1.0.5: resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + lcid@2.0.0: + resolution: {integrity: sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==} + engines: {node: '>=6'} + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + lodash.escaperegexp@4.1.2: resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} @@ -1190,6 +1294,10 @@ packages: resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} engines: {node: ^18.17.0 || >=20.5.0} + map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + matcher@3.0.0: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} @@ -1202,6 +1310,10 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + mem@4.3.0: + resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} + engines: {node: '>=6'} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -1296,6 +1408,10 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true + mldoc@1.5.9: + resolution: {integrity: sha512-87FQ7hseS87tsk+VdpIigpu8LH+GwmbbFgpxgFwvnbH5oOjmIrc47laH4Dyggzqiy8/vMjDHkl7vsId0eXhCDQ==} + hasBin: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1306,6 +1422,9 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + node-abi@4.28.0: resolution: {integrity: sha512-Qfp5XZL1cJDOabOT8H5gnqMTmM4NjvYzHp4I/Kt/Sl76OVkOBBHRFlPspGV0hYvMoqQsypFjT/Yp7Km0beXW9g==} engines: {node: '>=22.12.0'} @@ -1342,6 +1461,14 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} + npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1377,18 +1504,46 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + os-locale@3.1.0: + resolution: {integrity: sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==} + engines: {node: '>=6'} + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} + p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-is-promise@2.1.0: + resolution: {integrity: sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + p-map@7.0.4: resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1399,6 +1554,10 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@5.0.0: resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1407,6 +1566,10 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1542,6 +1705,9 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + remove-accents@0.5.0: + resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -1550,6 +1716,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@1.0.1: + resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + resedit@1.7.2: resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} engines: {node: '>=12', npm: '>=6'} @@ -1651,6 +1820,9 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -1660,10 +1832,18 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} @@ -1758,6 +1938,14 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + + string-width@2.1.1: + resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} + engines: {node: '>=4'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1766,12 +1954,24 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@8.2.0: + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@4.0.0: + resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} + engines: {node: '>=4'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1780,6 +1980,10 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + strip-eof@1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -1817,6 +2021,9 @@ packages: tiny-async-pool@1.3.0: resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + tiny-pinyin@1.3.2: + resolution: {integrity: sha512-uHNGu4evFt/8eNLldazeAM1M8JrMc1jshhJJfVRARTN3yT8HEEibofeQ7QETWQ5ISBjd6fKtTVBCC/+mGS6FpA==} + tiny-typed-emitter@2.1.0: resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} @@ -1913,6 +2120,13 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1923,6 +2137,10 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + wrap-ansi@2.1.0: + resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} + engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1934,6 +2152,18 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + wsl-utils@0.3.1: resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} engines: {node: '>=20'} @@ -1942,6 +2172,9 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -1956,10 +2189,16 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yargs-parser@11.1.1: + resolution: {integrity: sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@12.0.5: + resolution: {integrity: sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -2133,6 +2372,8 @@ snapshots: dependencies: minipass: 7.1.3 + '@js-joda/core@3.2.0': {} + '@malept/cross-spawn-promise@2.0.0': dependencies: cross-spawn: 7.0.6 @@ -2287,6 +2528,10 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-regex@2.1.1: {} + + ansi-regex@3.0.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -2487,6 +2732,8 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 + camelcase@5.3.1: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -2514,6 +2761,12 @@ snapshots: string-width: 4.2.3 optional: true + cliui@4.1.0: + dependencies: + string-width: 2.1.1 + strip-ansi: 4.0.0 + wrap-ansi: 2.1.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -2526,6 +2779,8 @@ snapshots: clone@1.0.4: {} + code-point-at@1.1.0: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2575,6 +2830,14 @@ snapshots: cross-dirname@0.1.0: optional: true + cross-spawn@6.0.6: + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2587,6 +2850,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -2831,6 +3096,16 @@ snapshots: dependencies: eventsource-parser: 3.0.7 + execa@1.0.0: + dependencies: + cross-spawn: 6.0.6 + get-stream: 4.1.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + expand-template@2.0.3: {} exponential-backoff@3.1.3: {} @@ -2974,6 +3249,10 @@ snapshots: fast-querystring: 1.1.2 safe-regex2: 5.1.0 + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -3036,8 +3315,14 @@ snapshots: function-bind@1.1.2: {} + fuse.js@7.1.0: {} + + get-caller-file@1.0.3: {} + get-caller-file@2.0.5: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3056,6 +3341,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@4.1.0: + dependencies: + pump: 3.0.4 + get-stream@5.2.0: dependencies: pump: 3.0.4 @@ -3202,6 +3491,8 @@ snapshots: ini@1.3.8: {} + invert-kv@2.0.0: {} + ip-address@10.1.0: {} ipaddr.js@1.9.1: {} @@ -3210,6 +3501,12 @@ snapshots: is-docker@3.0.0: {} + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-in-ssh@1.0.0: {} @@ -3224,6 +3521,8 @@ snapshots: is-promise@4.0.0: {} + is-stream@1.1.0: {} + is-unicode-supported@0.1.0: {} is-wsl@3.1.1: @@ -3305,6 +3604,10 @@ snapshots: lazy-val@1.0.5: {} + lcid@2.0.0: + dependencies: + invert-kv: 2.0.0 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -3315,6 +3618,11 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.2 + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + lodash.escaperegexp@4.1.2: {} lodash.isequal@4.5.0: {} @@ -3350,6 +3658,10 @@ snapshots: transitivePeerDependencies: - supports-color + map-age-cleaner@0.1.3: + dependencies: + p-defer: 1.0.0 + matcher@3.0.0: dependencies: escape-string-regexp: 4.0.0 @@ -3359,6 +3671,12 @@ snapshots: media-typer@1.1.0: {} + mem@4.3.0: + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 2.1.0 + p-is-promise: 2.1.0 + merge-descriptors@2.0.0: {} mime-db@1.52.0: {} @@ -3439,12 +3757,18 @@ snapshots: dependencies: minimist: 1.2.8 + mldoc@1.5.9: + dependencies: + yargs: 12.0.5 + ms@2.1.3: {} napi-build-utils@2.0.0: {} negotiator@1.0.0: {} + nice-try@1.0.5: {} + node-abi@4.28.0: dependencies: semver: 7.7.4 @@ -3487,6 +3811,12 @@ snapshots: normalize-url@6.1.0: {} + npm-run-path@2.0.2: + dependencies: + path-key: 2.0.1 + + number-is-nan@1.0.1: {} + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -3529,24 +3859,50 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + os-locale@3.1.0: + dependencies: + execa: 1.0.0 + lcid: 2.0.0 + mem: 4.3.0 + p-cancelable@2.1.1: {} + p-defer@1.0.0: {} + + p-finally@1.0.0: {} + + p-is-promise@2.1.0: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + p-map@7.0.4: {} + p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} pako@1.0.11: {} parseurl@1.3.3: {} + path-exists@3.0.0: {} + path-exists@5.0.0: {} path-is-absolute@1.0.1: {} + path-key@2.0.1: {} + path-key@3.1.1: {} path-scurry@1.11.1: @@ -3699,10 +4055,14 @@ snapshots: real-require@0.2.0: {} + remove-accents@0.5.0: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} + require-main-filename@1.0.1: {} + resedit@1.7.2: dependencies: pe-library: 0.4.1 @@ -3811,16 +4171,24 @@ snapshots: transitivePeerDependencies: - supports-color + set-blocking@2.0.0: {} + set-cookie-parser@2.7.2: {} setimmediate@1.0.5: {} setprototypeof@1.2.0: {} + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 + shebang-regex@1.0.0: {} + shebang-regex@3.0.0: {} side-channel-list@1.0.1: @@ -3929,6 +4297,17 @@ snapshots: statuses@2.0.2: {} + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + + string-width@2.1.1: + dependencies: + is-fullwidth-code-point: 2.0.0 + strip-ansi: 4.0.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -3941,6 +4320,11 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.2.0 + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -3949,6 +4333,14 @@ snapshots: dependencies: safe-buffer: 5.2.1 + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@4.0.0: + dependencies: + ansi-regex: 3.0.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -3957,6 +4349,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-eof@1.0.0: {} + strip-json-comments@2.0.1: {} sumchecker@3.0.1: @@ -4010,6 +4404,8 @@ snapshots: dependencies: semver: 5.7.2 + tiny-pinyin@1.3.2: {} + tiny-typed-emitter@2.1.0: {} tinyglobby@0.2.16: @@ -4098,6 +4494,12 @@ snapshots: web-streams-polyfill@3.3.3: {} + which-module@2.0.1: {} + + which@1.3.1: + dependencies: + isexe: 2.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -4106,6 +4508,11 @@ snapshots: dependencies: isexe: 3.1.5 + wrap-ansi@2.1.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -4120,6 +4527,8 @@ snapshots: wrappy@1.0.2: {} + ws@8.20.0: {} + wsl-utils@0.3.1: dependencies: is-wsl: 3.1.1 @@ -4127,6 +4536,8 @@ snapshots: xmlbuilder@15.1.1: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yaku@0.16.7: {} @@ -4135,8 +4546,28 @@ snapshots: yallist@5.0.0: {} + yargs-parser@11.1.1: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@12.0.5: + dependencies: + cliui: 4.1.0 + decamelize: 1.2.0 + find-up: 3.0.0 + get-caller-file: 1.0.3 + os-locale: 3.1.0 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 2.1.1 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 11.1.1 + yargs@17.7.2: dependencies: cliui: 8.0.1 diff --git a/scripts/build-db-worker-node-bundle.mjs b/scripts/build-db-worker-node-bundle.mjs index 2dbbfd0745..a3810c1281 100644 --- a/scripts/build-db-worker-node-bundle.mjs +++ b/scripts/build-db-worker-node-bundle.mjs @@ -18,6 +18,10 @@ const builtinModuleSet = new Set([ ...builtinModules, ...builtinModules.map((moduleName) => `node:${moduleName}`), ]); +const externalModuleSet = new Set([ + "keytar", + "ws", +]); async function exists(targetPath) { try { @@ -101,7 +105,10 @@ async function main() { }, rollupOptions: { external: (id) => - id.endsWith(".node") || id.startsWith("node:") || builtinModuleSet.has(id), + id.endsWith(".node") || + id.startsWith("node:") || + builtinModuleSet.has(id) || + externalModuleSet.has(id), output: { format: "cjs", exports: "auto", @@ -116,6 +123,18 @@ async function main() { throw new Error(`vite bundle missing output file: ${bundleEntry}`); } + const bundleContents = await fs.readFile(bundleEntry, "utf8"); + if (bundleContents.includes("node_modules/.pnpm/keytar")) { + throw new Error( + "vite bundle contains a pnpm keytar native path; keytar must stay external" + ); + } + if (bundleContents.includes("ws does not work in the browser")) { + throw new Error( + "vite bundle contains the ws browser stub; ws must stay external" + ); + } + let filesAfter = await listFilesRecursive(distDir); if (filesAfter.includes("index.html") && !filesBefore.includes("index.html")) { await removeIfExists(path.join(distDir, "index.html")); diff --git a/scripts/prepare-desktop-runtime-js.mjs b/scripts/prepare-desktop-runtime-js.mjs new file mode 100644 index 0000000000..98dfb4d455 --- /dev/null +++ b/scripts/prepare-desktop-runtime-js.mjs @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +import { promises as fs } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, ".."); + +const staticDir = path.join(repoRoot, "static"); +const staticJsDir = path.join(staticDir, "js"); +const distDir = path.join(repoRoot, "dist"); + +const copyPairs = [ + { + from: path.join(staticDir, "logseq-cli.js"), + to: path.join(staticJsDir, "logseq-cli.js"), + }, + { + from: path.join(staticDir, "logseq-cli.js.map"), + to: path.join(staticJsDir, "logseq-cli.js.map"), + optional: true, + }, + { + from: path.join(distDir, "db-worker-node.js"), + to: path.join(staticJsDir, "db-worker-node.js"), + }, +]; + +async function exists(filePath) { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +async function copyOne({ from, to, optional = false }) { + if (!(await exists(from))) { + if (optional) return; + throw new Error(`missing required source file: ${from}`); + } + await fs.copyFile(from, to); +} + +async function main() { + await fs.mkdir(staticJsDir, { recursive: true }); + + for (const pair of copyPairs) { + await copyOne(pair); + } + + // Keep release app runtime files only in static/js. + await fs.rm(path.join(staticDir, "logseq-cli.js"), { force: true }); + await fs.rm(path.join(staticDir, "logseq-cli.js.map"), { force: true }); + await fs.rm(path.join(staticDir, "db-worker-node.js"), { force: true }); + await fs.rm(path.join(staticDir, "db-worker-node.js.map"), { force: true }); +} + +main().catch((error) => { + console.error(`[prepare-desktop-runtime-js] ${error.message}`); + process.exit(1); +}); diff --git a/src/electron/electron/core.cljs b/src/electron/electron/core.cljs index 3745401cbd..70dde33895 100644 --- a/src/electron/electron/core.cljs +++ b/src/electron/electron/core.cljs @@ -1,6 +1,7 @@ (ns electron.core (:require ["/electron/utils" :as js-utils] ["electron" :refer [BrowserWindow Menu app protocol ipcMain dialog shell] :as electron] + ["fs-extra" :as fs] ["os" :as os] ["path" :as node-path] @@ -34,6 +35,7 @@ (defonce *setup-fn (volatile! nil)) (defonce *teardown-fn (volatile! nil)) (defonce *quit-dirty? (volatile! true)) +(defonce CLI_LAUNCHER_MARKER "logseq-cli-managed") (defn setup-updater! [^js win] ;; manual/auto updater @@ -266,6 +268,119 @@ (fn [error] (logger/warn :electron/wrong-release-warning-failed error)))))) +(defn- path-separator + [] + (if utils/win32? ";" ":")) + +(defn- split-path-env + [path-env] + (->> (string/split (or path-env "") (re-pattern (path-separator))) + (remove string/blank?) + distinct)) + +(defn- writable-dir? + [dir] + (try + (when (and (string? dir) + (fs/existsSync dir) + (.isDirectory (fs/statSync dir))) + (fs/accessSync dir (aget fs "constants" "W_OK")) + true) + (catch :default _ + false))) + +(defn- find-first-writable-dir + [dirs] + (some #(when (writable-dir? %) %) dirs)) + +(defn- ensure-dir! + [dir] + (when (and (string? dir) (not (fs/existsSync dir))) + (fs/mkdirSync dir #js {:recursive true}))) + +(defn- preferred-unix-cli-dir + [] + (let [path-dirs (split-path-env (.-PATH js/process.env)) + user-bin (node-path/join (.homedir os) ".local" "bin")] + (or (find-first-writable-dir path-dirs) + (do + (ensure-dir! user-bin) + (when (writable-dir? user-bin) + user-bin))))) + +(defn- preferred-win-cli-dir + [] + (let [path-env (or (.-PATH js/process.env) (.-Path js/process.env)) + path-dirs (split-path-env path-env) + local-appdata (.-LOCALAPPDATA js/process.env) + windows-apps-dir (when local-appdata + (node-path/join local-appdata "Microsoft" "WindowsApps"))] + (or (when windows-apps-dir + (ensure-dir! windows-apps-dir) + (when (writable-dir? windows-apps-dir) + windows-apps-dir)) + (find-first-writable-dir path-dirs)))) + +(defn- cli-script-path + [] + (if (.-isPackaged ^js app) + (node-path/join js/process.resourcesPath "app.asar" "js" "logseq-cli.js") + (node-path/join js/__dirname "logseq-cli.js"))) + +(defn- render-unix-cli-launcher + [exe-path cli-path] + (str "#!/usr/bin/env sh\n" + "# " CLI_LAUNCHER_MARKER "\n" + "set -eu\n" + "ELECTRON_RUN_AS_NODE=1 exec \"" exe-path "\" \"" cli-path "\" \"$@\"\n")) + +(defn- render-win-cli-launcher + [exe-path cli-path] + (str "@echo off\r\n" + "REM " CLI_LAUNCHER_MARKER "\r\n" + "set ELECTRON_RUN_AS_NODE=1\r\n" + "\"" exe-path "\" \"" cli-path "\" %*\r\n")) + +(defn- write-cli-launcher! + [path content windows?] + (let [should-write? (if (fs/existsSync path) + (let [existing (.readFileSync fs path "utf8")] + (and (string/includes? existing CLI_LAUNCHER_MARKER) + (not= existing content))) + true)] + (when should-write? + (.writeFileSync fs path content "utf8") + (when-not windows? + (fs/chmodSync path "755")) + true))) + +(defn- install-cli-launcher! + [] + (try + (let [cli-path (cli-script-path) + cli-dir (if utils/win32? + (preferred-win-cli-dir) + (preferred-unix-cli-dir))] + (cond + (not (fs/existsSync cli-path)) + (logger/warn :cli/install (str "Missing CLI script at " cli-path ", skip installing launcher")) + + (nil? cli-dir) + (logger/warn :cli/install "No writable PATH directory found; skip installing logseq launcher") + + :else + (let [target-path (if utils/win32? + (node-path/join cli-dir "logseq.cmd") + (node-path/join cli-dir "logseq")) + exe-path (.getPath app "exe") + content (if utils/win32? + (render-win-cli-launcher exe-path cli-path) + (render-unix-cli-launcher exe-path cli-path))] + (when (write-cli-launcher! target-path content utils/win32?) + (logger/info :cli/install (str "Installed launcher at " target-path)))))) + (catch :default e + (logger/warn :cli/install "Failed to install logseq launcher" e)))) + (defn- on-app-ready! [^js app'] (.on app' "ready" @@ -286,6 +401,7 @@ (js-utils/disableXFrameOptions win) (db/ensure-graphs-dir!) + (install-cli-launcher!) ;; Windows/Linux: handle deeplink URL passed on first launch via argv (handle-initial-deeplink! win) diff --git a/src/main/frontend/worker/platform/node.cljs b/src/main/frontend/worker/platform/node.cljs index 22c985c051..a92ba9adaf 100644 --- a/src/main/frontend/worker/platform/node.cljs +++ b/src/main/frontend/worker/platform/node.cljs @@ -4,7 +4,6 @@ ["node:sqlite" :as node-sqlite] ["os" :as os] ["path" :as node-path] - ["ws" :as ws] [clojure.string :as string] [cognitect.transit :as transit] [frontend.worker.db-worker-node-lock :as db-lock] @@ -290,7 +289,8 @@ (defn- websocket-connect [url] - (ws. url)) + (let [WebSocket (js/require "ws")] + (new WebSocket url))) (def ^:private kv-transit-writer (transit/writer diff --git a/src/main/logseq/cli/command/doctor.cljs b/src/main/logseq/cli/command/doctor.cljs index babd89ed18..14a2d94df4 100644 --- a/src/main/logseq/cli/command/doctor.cljs +++ b/src/main/logseq/cli/command/doctor.cljs @@ -13,7 +13,7 @@ [(core/command-entry ["doctor"] :doctor "Run runtime diagnostics" - {:dev-script {:desc "Check static/db-worker-node.js instead of bundled dist runtime" + {:dev-script {:desc "Check static/db-worker-node.js instead of packaged js runtime" :coerce :boolean}} {:examples ["logseq doctor --dev-script"]})]) diff --git a/src/main/logseq/cli/server.cljs b/src/main/logseq/cli/server.cljs index 861723b427..1bbbe8589e 100644 --- a/src/main/logseq/cli/server.cljs +++ b/src/main/logseq/cli/server.cljs @@ -60,11 +60,15 @@ [] (node-path/join js/__dirname "../static/db-worker-node.js")) +(defn- db-worker-release-script-path + [] + (node-path/join js/__dirname "js" "db-worker-node.js")) + (defn db-worker-script-path [] (if goog.DEBUG (db-worker-dev-script-path) - (node-path/join js/__dirname "../dist/db-worker-node.js"))) + (db-worker-release-script-path))) (defn db-worker-runtime-script-path [] diff --git a/src/test/logseq/cli/command/doctor_test.cljs b/src/test/logseq/cli/command/doctor_test.cljs index 386db0f187..9ba8424283 100644 --- a/src/test/logseq/cli/command/doctor_test.cljs +++ b/src/test/logseq/cli/command/doctor_test.cljs @@ -165,13 +165,13 @@ {:ok? true :check {:id :db-worker-script :status :ok - :path "/dist/db-worker-node.js" - :message (str "Found readable file: " "/dist/db-worker-node.js")}})] + :path "/js/db-worker-node.js" + :message (str "Found readable file: " "/js/db-worker-node.js")}})] (p/let [result (commands/execute {:type :doctor} {:root-dir "/tmp/logseq-doctor"}) checked-path (get-in result [:data :checks 0 :path])] (is (= :ok (:status result))) - (is (string/ends-with? checked-path "/dist/db-worker-node.js")))) + (is (string/ends-with? checked-path "/js/db-worker-node.js")))) (p/catch (fn [e] (is false (str "unexpected error: " e)))) (p/finally done))))