From ba4c2a11f6777428654ab0060f0b9779faef5064 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 11:53:20 +0800 Subject: [PATCH 01/10] Delete verify-executable.js --- scripts/verify-executable.js | 143 ----------------------------------- 1 file changed, 143 deletions(-) delete mode 100644 scripts/verify-executable.js diff --git a/scripts/verify-executable.js b/scripts/verify-executable.js deleted file mode 100644 index 1fe8edab..00000000 --- a/scripts/verify-executable.js +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env node -/** - * Verify that a packaged Electron executable starts correctly. - * This script launches the executable and checks that the RPC port (9138) becomes available. - */ - -import { spawn } from 'child_process'; -import { existsSync } from 'fs'; -import { createServer } from 'net'; - -const executablePath = process.argv[2]; -const rpcPort = 9138; -const timeout = 30000; // 30 seconds - -if (!executablePath) { - console.error('Usage: node scripts/verify-executable.js '); - process.exit(1); -} - -if (!existsSync(executablePath)) { - console.error(`Error: Executable not found: ${executablePath}`); - process.exit(1); -} - -console.log(`Starting executable: ${executablePath}`); -console.log(`Checking for RPC port ${rpcPort}...`); - -// Start the executable -const appProcess = spawn(executablePath, [], { - detached: false, - stdio: 'pipe', -}); - -let appExited = false; -let portAvailable = false; -let timeoutId; - -// Check if port is in use (app is running) -function checkPort() { - return new Promise((resolve) => { - const server = createServer(); - server.listen(rpcPort, '127.0.0.1', () => { - server.close(); - resolve(false); // Port is available (not in use yet) - }); - server.on('error', (err) => { - if (err.code === 'EADDRINUSE') { - resolve(true); // Port is in use (app is running - success!) - } else { - resolve(false); - } - }); - }); -} - -// Monitor app process -appProcess.on('exit', (code, signal) => { - appExited = true; - if (code !== null && code !== 0) { - console.error(`App exited with code ${code}`); - cleanup(); - process.exit(1); - } -}); - -appProcess.stderr.on('data', (data) => { - const text = data.toString(); - // Filter out common harmless errors - if (!text.includes('Gtk') && !text.includes('libnotify')) { - console.error('stderr:', text); - } -}); - -// Poll for port availability -async function pollPort() { - const maxAttempts = 30; // 30 attempts over 30 seconds - let attempts = 0; - let pollTimeoutId; - - const tick = async () => { - attempts++; - const inUse = await checkPort(); - - if (inUse) { - portAvailable = true; - console.log(`✓ RPC port ${rpcPort} is in use (app is running)`); - clearTimeout(pollTimeoutId); - clearTimeout(timeoutId); - cleanup(); - process.exit(0); - return; - } - - if (attempts >= maxAttempts || appExited) { - clearTimeout(pollTimeoutId); - clearTimeout(timeoutId); - if (!portAvailable) { - console.error(`✗ RPC port ${rpcPort} did not become available within ${timeout / 1000} seconds`); - cleanup(); - process.exit(1); - } - return; - } - - pollTimeoutId = setTimeout(tick, 1000); - }; - - pollTimeoutId = setTimeout(tick, 1000); -} - -// Set overall timeout -timeoutId = setTimeout(() => { - if (!portAvailable) { - console.error(`✗ Timeout: RPC port ${rpcPort} did not become available within ${timeout / 1000} seconds`); - cleanup(); - process.exit(1); - } -}, timeout); - -function cleanup() { - try { - if (appProcess && !appProcess.killed) { - appProcess.kill(); - // Also try to kill any child processes - if (appProcess.pid) { - try { - process.kill(appProcess.pid, 'SIGTERM'); - } catch (e) { - // Ignore errors - } - } - } - } catch (e) { - // Ignore cleanup errors - } -} - -// Handle process termination -process.on('SIGINT', cleanup); -process.on('SIGTERM', cleanup); - -// Start polling -pollPort(); From a45a6456bbc1621ae11852a244f9867af848e7a0 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 11:59:06 +0800 Subject: [PATCH 02/10] fix script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a376f73c..c84d5845 100755 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "preview": "vite preview", "analyze-bundle": "cross-env NODE_ENV=production PUBLIC_URL=./ GENERATE_SOURCEMAP=true vite build && npx source-map-explorer 'build/assets/*.js'", "electron": "yarn build:preload && cross-env ELECTRON_IS_DEV=1 yarn electron:before && cross-env ELECTRON_IS_DEV=1 electron .", - "electron:no-delete-data": "yarn electron:before:delete-data && electron .", + "electron:no-delete-data": "yarn build:preload && yarn electron-rebuild && electron .", "electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron\"", "electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron:no-delete-data\"", "electron:package": "yarn build && yarn build:preload && electron-forge package", From 05afd1ce29d16a73c3586357d1c83d1bbfceb554 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 12:00:27 +0800 Subject: [PATCH 03/10] refactor: extract timeout management into useScheduledReset hook --- .../error-display/error-display.tsx | 28 +++------------ .../post/comment-tools/comment-tools.tsx | 24 +++---------- src/hooks/use-scheduled-reset.ts | 35 +++++++++++++++++++ 3 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 src/hooks/use-scheduled-reset.ts diff --git a/src/components/error-display/error-display.tsx b/src/components/error-display/error-display.tsx index 6cb56bd8..c3538b0c 100644 --- a/src/components/error-display/error-display.tsx +++ b/src/components/error-display/error-display.tsx @@ -1,5 +1,6 @@ -import { useEffect, useRef, useState } from 'react'; +import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import useScheduledReset from '../../hooks/use-scheduled-reset'; import { copyToClipboard } from '../../lib/utils/clipboard-utils'; import styles from './error-display.module.css'; @@ -46,30 +47,11 @@ const ErrorDisplay = ({ error }: { error: unknown }) => { const { t } = useTranslation(); const [feedbackMessageKey, setFeedbackMessageKey] = useState(null); const errorDetails = getErrorDetails(error); - const feedbackTimeoutRef = useRef | null>(null); - const originalDisplayMessage = errorDetails?.message ? `${t('error')}: ${errorDetails.message}` : null; - - const clearFeedbackTimeout = () => { - if (feedbackTimeoutRef.current) { - clearTimeout(feedbackTimeoutRef.current); - feedbackTimeoutRef.current = null; - } - }; + const resetFeedback = useCallback(() => setFeedbackMessageKey(null), []); + const [scheduleFeedbackReset] = useScheduledReset(resetFeedback, 1500); - const scheduleFeedbackReset = () => { - clearFeedbackTimeout(); - feedbackTimeoutRef.current = setTimeout(() => { - setFeedbackMessageKey(null); - feedbackTimeoutRef.current = null; - }, 1500); - }; - - useEffect(() => { - return () => { - clearFeedbackTimeout(); - }; - }, []); + const originalDisplayMessage = errorDetails?.message ? `${t('error')}: ${errorDetails.message}` : null; const handleMessageClick = async () => { if (!errorDetails?.message || feedbackMessageKey) return; diff --git a/src/components/post/comment-tools/comment-tools.tsx b/src/components/post/comment-tools/comment-tools.tsx index 0fb35f8d..83a983c4 100644 --- a/src/components/post/comment-tools/comment-tools.tsx +++ b/src/components/post/comment-tools/comment-tools.tsx @@ -1,7 +1,8 @@ -import { useEffect, useRef, useState } from 'react'; +import { useCallback, useState } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Author, useAccount, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import useScheduledReset from '../../../hooks/use-scheduled-reset'; import styles from './comment-tools.module.css'; import EditMenu from './edit-menu'; import HideMenu from './hide-menu'; @@ -59,24 +60,9 @@ const ModOrReportButton = ({ cid, isAuthor, isAccountMod, isCommentAuthorMod }: const ShareButton = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: string }) => { const { t } = useTranslation(); const [hasCopied, setHasCopied] = useState(false); - const resetTimeoutRef = useRef | null>(null); - const clearResetTimeout = () => { - if (resetTimeoutRef.current) { - clearTimeout(resetTimeoutRef.current); - resetTimeoutRef.current = null; - } - }; - - const scheduleReset = () => { - clearResetTimeout(); - resetTimeoutRef.current = setTimeout(() => { - setHasCopied(false); - resetTimeoutRef.current = null; - }, 2000); - }; - - useEffect(() => () => clearResetTimeout(), []); + const resetCopied = useCallback(() => setHasCopied(false), []); + const [scheduleReset, clearReset] = useScheduledReset(resetCopied, 2000); const handleCopy = async () => { try { @@ -86,7 +72,7 @@ const ShareButton = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddres } catch (error) { console.error('Failed to copy share link:', error); setHasCopied(false); - clearResetTimeout(); + clearReset(); } }; diff --git a/src/hooks/use-scheduled-reset.ts b/src/hooks/use-scheduled-reset.ts new file mode 100644 index 00000000..38ada32a --- /dev/null +++ b/src/hooks/use-scheduled-reset.ts @@ -0,0 +1,35 @@ +import { useCallback, useEffect, useRef } from 'react'; + +/** + * A hook for managing scheduled state resets with automatic cleanup. + * Useful for temporary UI feedback (e.g., "copied!" messages that auto-dismiss). + * + * @param callback - The function to call when the timeout fires + * @param delay - The delay in milliseconds before the callback is called + * @returns [scheduleReset, clearReset] - Functions to schedule or cancel the reset + */ +const useScheduledReset = (callback: () => void, delay: number): [() => void, () => void] => { + const timeoutRef = useRef | null>(null); + + const clearReset = useCallback(() => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + }, []); + + const scheduleReset = useCallback(() => { + clearReset(); + timeoutRef.current = setTimeout(() => { + callback(); + timeoutRef.current = null; + }, delay); + }, [callback, delay, clearReset]); + + // Cleanup on unmount + useEffect(() => clearReset, [clearReset]); + + return [scheduleReset, clearReset]; +}; + +export default useScheduledReset; From 47b847f8d9c1aa27c18a790b9b701df112f83ff6 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 12:04:38 +0800 Subject: [PATCH 04/10] Add rewrite rule to vercel.json Introduces a rewrite rule to route all requests to index.html, which is useful for single-page applications using client-side routing. --- vercel.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vercel.json b/vercel.json index cee23b90..5db2d17c 100644 --- a/vercel.json +++ b/vercel.json @@ -1,4 +1,7 @@ { + "rewrites": [ + { "source": "/(.*)", "destination": "/index.html" } + ], "buildCommand": "yarn build", "outputDirectory": "build", "framework": "vite" From 61c470141b2d4859632b55d9f16afbfdc7c286b0 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 12:16:09 +0800 Subject: [PATCH 05/10] refactor(electron): migrate build-docker.sh to Electron Forge and add arch-specific scripts Updated build-docker.sh to use Electron Forge instead of electron-builder, switched from electronuserland/builder image to node:22, and removed electron-builder-specific commands. Added architecture-specific build scripts (linux:x64, linux:arm64, mac:x64, mac:arm64) to package.json for CI workflow. Removed outdated electron-rebuild comment from release.yml. --- .github/workflows/release.yml | 2 +- electron/build-docker.sh | 27 ++++++++++++--------------- package.json | 4 ++++ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d72782ba..77b2cfab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,7 +128,7 @@ jobs: with: # needed for git commit history changelog fetch-depth: 0 - - name: Setup Node.js v22 # electron-rebuild needs Node 22+ + - name: Setup Node.js v22 uses: actions/setup-node@v2 with: node-version: 22 diff --git a/electron/build-docker.sh b/electron/build-docker.sh index d33b917b..af87ec19 100755 --- a/electron/build-docker.sh +++ b/electron/build-docker.sh @@ -11,7 +11,7 @@ fi node electron/download-ipfs || { echo "Error: failed script 'node electron/download-ipfs'" ; exit 1; } dockerfile=' -FROM electronuserland/builder:16 +FROM node:22 # install node_modules WORKDIR /usr/src/seedit @@ -19,44 +19,41 @@ COPY ./package.json . COPY ./yarn.lock . RUN yarn -# build native dependencies like sqlite3 -RUN electron-builder install-app-deps - -# copy source files +# copy source files and configs COPY ./bin ./bin COPY ./electron ./electron COPY ./src ./src COPY ./public ./public - -# required or yarn build fails -COPY ./.eslintrc.json ./.eslintrc.json -COPY ./.prettierrc ./.prettierrc +COPY ./forge.config.js ./forge.config.js +COPY ./vite.config.js ./vite.config.js +COPY ./tsconfig.json ./tsconfig.json +COPY ./index.html ./index.html # react build RUN yarn build ' -# build electron-builder docker image +# build electron-forge docker image # temporary .dockerignore to save build time echo $'node_modules\ndist' > .dockerignore echo "$dockerfile" | sudo docker build \ . \ - --tag seedit-electron-builder \ + --tag seedit-electron-forge \ --file - rm .dockerignore # build linux binary sudo docker run \ - --name seedit-electron-builder \ + --name seedit-electron-forge \ --volume "$root_path"/dist:/usr/src/seedit/dist \ --rm \ - seedit-electron-builder \ + seedit-electron-forge \ yarn electron:build:linux # build windows binary sudo docker run \ - --name seedit-electron-builder \ + --name seedit-electron-forge \ --volume "$root_path"/dist:/usr/src/seedit/dist \ --rm \ - seedit-electron-builder \ + seedit-electron-forge \ yarn electron:build:windows diff --git a/package.json b/package.json index c84d5845..e188eb6c 100755 --- a/package.json +++ b/package.json @@ -71,6 +71,10 @@ "electron:build:linux": "yarn build && yarn build:preload && electron-forge make --platform=linux", "electron:build:mac": "yarn build && yarn build:preload && electron-forge make --platform=darwin", "electron:build:windows": "yarn build && yarn build:preload && electron-forge make --platform=win32", + "electron:build:linux:x64": "yarn build && yarn build:preload && electron-forge make --platform=linux --arch=x64", + "electron:build:linux:arm64": "yarn build && yarn build:preload && electron-forge make --platform=linux --arch=arm64", + "electron:build:mac:x64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=x64", + "electron:build:mac:arm64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=arm64", "electron:before": "yarn electron-rebuild && yarn electron:before:delete-data", "electron:before:delete-data": "rimraf .plebbit", "android:build:icons": "cordova-res android --skip-config --copy --resources /tmp/plebbit-react-android-icons --icon-source ./android/icons/icon.png --splash-source ./android/icons/splash.png --icon-foreground-source ./android/icons/icon-foreground.png --icon-background-source '#ffffee'", From e1575de5fc79d871959e6b977e4756d16bbfb3df Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 13:11:44 +0800 Subject: [PATCH 06/10] fix(electron): fix production build crashes --- electron/before-pack.js | 3 ++- index.html | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/electron/before-pack.js b/electron/before-pack.js index 9d92d938..775855be 100755 --- a/electron/before-pack.js +++ b/electron/before-pack.js @@ -18,7 +18,8 @@ const ipfsClientLinuxPath = path.join(ipfsClientsPath, 'linux'); // const ipfsClientLinuxUrl = `https://github.com/plebbit/kubo/releases/download/v${ipfsClientVersion}/ipfs-linux-amd64` // official kubo download links https://docs.ipfs.tech/install/command-line/#install-official-binary-distributions -const ipfsClientVersion = '0.32.1'; +// NOTE: Keep this version in sync with the kubo version in package.json to avoid repo version mismatches +const ipfsClientVersion = '0.39.0'; // Resolve desired build arch: allow overriding via env (so cross-arch builds pick correct binary) const resolveBuildArch = () => { diff --git a/index.html b/index.html index d60a5352..042ae75b 100644 --- a/index.html +++ b/index.html @@ -18,7 +18,14 @@ From 969891e0d9bb849eaab414399e457d8e789fe002 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 13:18:42 +0800 Subject: [PATCH 07/10] chore(deps): electron-rebuild and related dependencies --- package.json | 5 +- yarn.lock | 153 ++++----------------------------------------------- 2 files changed, 12 insertions(+), 146 deletions(-) diff --git a/package.json b/package.json index e188eb6c..85ad03f8 100755 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "preview": "vite preview", "analyze-bundle": "cross-env NODE_ENV=production PUBLIC_URL=./ GENERATE_SOURCEMAP=true vite build && npx source-map-explorer 'build/assets/*.js'", "electron": "yarn build:preload && cross-env ELECTRON_IS_DEV=1 yarn electron:before && cross-env ELECTRON_IS_DEV=1 electron .", - "electron:no-delete-data": "yarn build:preload && yarn electron-rebuild && electron .", + "electron:no-delete-data": "yarn build:preload && electron .", "electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron\"", "electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron:no-delete-data\"", "electron:package": "yarn build && yarn build:preload && electron-forge package", @@ -75,7 +75,7 @@ "electron:build:linux:arm64": "yarn build && yarn build:preload && electron-forge make --platform=linux --arch=arm64", "electron:build:mac:x64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=x64", "electron:build:mac:arm64": "yarn build && yarn build:preload && electron-forge make --platform=darwin --arch=arm64", - "electron:before": "yarn electron-rebuild && yarn electron:before:delete-data", + "electron:before": "yarn electron:before:delete-data", "electron:before:delete-data": "rimraf .plebbit", "android:build:icons": "cordova-res android --skip-config --copy --resources /tmp/plebbit-react-android-icons --icon-source ./android/icons/icon.png --splash-source ./android/icons/splash.png --icon-foreground-source ./android/icons/icon-foreground.png --icon-background-source '#ffffee'", "prettier": "oxfmt src/**/*.{js,ts,tsx} electron/**/*.{js,mjs}", @@ -107,7 +107,6 @@ "@electron-forge/maker-squirrel": "7.6.0", "@electron-forge/maker-zip": "7.6.0", "@electron-forge/plugin-auto-unpack-natives": "7.6.0", - "@electron/rebuild": "4.0.1", "@react-scan/vite-plugin-react-scan": "0.1.8", "@types/memoizee": "0.4.9", "@types/node-fetch": "2", diff --git a/yarn.lock b/yarn.lock index 9807730c..4388d647 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1447,26 +1447,6 @@ semver "^7.1.3" yargs-parser "^21.1.1" -"@electron/rebuild@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-4.0.1.tgz#0620d5bb71a0b8b09a86fb9fa979244e1fcc10bf" - integrity sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q== - dependencies: - "@malept/cross-spawn-promise" "^2.0.0" - chalk "^4.0.0" - debug "^4.1.1" - detect-libc "^2.0.1" - got "^11.7.0" - graceful-fs "^4.2.11" - node-abi "^4.2.0" - node-api-version "^0.2.1" - node-gyp "^11.2.0" - ora "^5.1.0" - read-binary-file-arch "^1.0.6" - semver "^7.3.5" - tar "^6.0.5" - yargs "^17.0.1" - "@electron/rebuild@^3.7.0": version "3.7.2" resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-3.7.2.tgz#8d808b29159c50086d27a5dec72b40bf16b4b582" @@ -3800,17 +3780,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/agent@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-3.0.0.tgz#1685b1fbd4a1b7bb4f930cbb68ce801edfe7aa44" - integrity sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q== - dependencies: - agent-base "^7.1.0" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.1" - lru-cache "^10.0.1" - socks-proxy-agent "^8.0.3" - "@npmcli/fs@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-4.0.0.tgz#a1eb1aeddefd2a4a347eca0fab30bc62c0e1c0f2" @@ -5230,11 +5199,6 @@ abbrev@1, abbrev@^1.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abbrev@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-3.0.1.tgz#8ac8b3b5024d31464fe2a5feeea9f4536bf44025" - integrity sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg== - abitype@1.2.3, abitype@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" @@ -5300,7 +5264,7 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" -agent-base@^7.1.0, agent-base@^7.1.2: +agent-base@^7.1.2: version "7.1.4" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== @@ -6025,7 +5989,7 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== -cacache@19.0.1, cacache@^15.2.0, cacache@^16.1.0, cacache@^19.0.1: +cacache@19.0.1, cacache@^15.2.0, cacache@^16.1.0: version "19.0.1" resolved "https://registry.yarnpkg.com/cacache/-/cacache-19.0.1.tgz#3370cc28a758434c85c2585008bd5bdcff17d6cd" integrity sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ== @@ -8568,7 +8532,7 @@ got@^11.7.0, got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -graceful-fs@^4.1.10, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6: +graceful-fs@^4.1.10, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -8923,7 +8887,7 @@ htmlparser2@^10.0.0: domutils "^3.2.1" entities "^6.0.0" -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== @@ -8946,14 +8910,6 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" - integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - http-proxy@1.18.1: version "1.18.1" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" @@ -8984,7 +8940,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.6: +https-proxy-agent@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== @@ -9781,11 +9737,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isexe@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" - integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== - iso-random-stream@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/iso-random-stream/-/iso-random-stream-2.0.2.tgz#a24f77c34cfdad9d398707d522a6a0cc640ff27d" @@ -10811,23 +10762,6 @@ make-fetch-happen@^10.2.1: socks-proxy-agent "^7.0.0" ssri "^9.0.0" -make-fetch-happen@^14.0.3: - version "14.0.3" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz#d74c3ecb0028f08ab604011e0bc6baed483fcdcd" - integrity sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ== - dependencies: - "@npmcli/agent" "^3.0.0" - cacache "^19.0.1" - http-cache-semantics "^4.1.1" - minipass "^7.0.2" - minipass-fetch "^4.0.0" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^1.0.0" - proc-log "^5.0.0" - promise-retry "^2.0.1" - ssri "^12.0.0" - make-fetch-happen@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" @@ -11787,17 +11721,6 @@ minipass-fetch@^2.0.3: optionalDependencies: encoding "^0.1.13" -minipass-fetch@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-4.0.1.tgz#f2d717d5a418ad0b1a7274f9b913515d3e78f9e5" - integrity sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ== - dependencies: - minipass "^7.0.3" - minipass-sized "^1.0.3" - minizlib "^3.0.1" - optionalDependencies: - encoding "^0.1.13" - minipass-flush@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" @@ -11831,7 +11754,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4, minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.0.4, minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -11844,7 +11767,7 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -minizlib@^3.0.1, minizlib@^3.1.0: +minizlib@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.1.0.tgz#6ad76c3a8f10227c9b51d1c9ac8e30b27f5a251c" integrity sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw== @@ -12046,11 +11969,6 @@ negotiator@^0.6.2, negotiator@^0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== -negotiator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" - integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== - neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -12078,19 +11996,12 @@ node-abi@^3.3.0, node-abi@^3.45.0: dependencies: semver "^7.3.5" -node-abi@^4.2.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-4.14.0.tgz#7846b36a732f1afa221be3ca0e6248448bc111ef" - integrity sha512-E4n91K4Nk1Rch2KzD+edU2bfZTP4W42GypAUDXU4vu1A+4u9PvUNDkGI0dXbsy8ZeF3WGj0SD/uHxnXD/sW+3w== - dependencies: - semver "^7.6.3" - node-addon-api@^7.0.0: version "7.1.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== -node-api-version@^0.2.0, node-api-version@^0.2.1: +node-api-version@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9" integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q== @@ -12137,22 +12048,6 @@ node-gyp@8.x: tar "^6.1.2" which "^2.0.2" -node-gyp@^11.2.0: - version "11.4.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-11.4.2.tgz#bb74cc6a80a0cc301811c8efd755fac39efc7cd0" - integrity sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ== - dependencies: - env-paths "^2.2.0" - exponential-backoff "^3.1.1" - graceful-fs "^4.2.6" - make-fetch-happen "^14.0.3" - nopt "^8.0.0" - proc-log "^5.0.0" - semver "^7.3.5" - tar "^7.4.3" - tinyglobby "^0.2.12" - which "^5.0.0" - node-releases@^2.0.21: version "2.0.21" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.21.tgz#f59b018bc0048044be2d4c4c04e4c8b18160894c" @@ -12210,13 +12105,6 @@ nopt@^6.0.0: dependencies: abbrev "^1.0.0" -nopt@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-8.1.0.tgz#b11d38caf0f8643ce885818518064127f602eae3" - integrity sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A== - dependencies: - abbrev "^3.0.0" - normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -13032,11 +12920,6 @@ proc-log@^2.0.1: resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw== -proc-log@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-5.0.0.tgz#e6c93cf37aef33f835c53485f314f50ea906a9d8" - integrity sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ== - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -14320,16 +14203,7 @@ socks-proxy-agent@^7.0.0: debug "^4.3.3" socks "^2.6.2" -socks-proxy-agent@^8.0.3: - version "8.0.5" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" - integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== - dependencies: - agent-base "^7.1.2" - debug "^4.3.4" - socks "^2.8.3" - -socks@^2.6.2, socks@^2.8.3: +socks@^2.6.2: version "2.8.7" resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea" integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== @@ -15014,7 +14888,7 @@ tinycache@1.1.2: dependencies: js-sizeof "0.0.1" -tinyglobby@^0.2.10, tinyglobby@^0.2.12, tinyglobby@^0.2.15: +tinyglobby@^0.2.10, tinyglobby@^0.2.15: version "0.2.15" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== @@ -15951,13 +15825,6 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -which@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/which/-/which-5.0.0.tgz#d93f2d93f79834d4363c7d0c23e00d07c466c8d6" - integrity sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ== - dependencies: - isexe "^3.1.1" - wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" From 9300befd1a29a66eafe607ff35a7bbd38f3a188d Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 13:36:15 +0800 Subject: [PATCH 08/10] fix(package.json): remove unneeded var --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85ad03f8..0d53dd76 100755 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "test": "vitest", "preview": "vite preview", "analyze-bundle": "cross-env NODE_ENV=production PUBLIC_URL=./ GENERATE_SOURCEMAP=true vite build && npx source-map-explorer 'build/assets/*.js'", - "electron": "yarn build:preload && cross-env ELECTRON_IS_DEV=1 yarn electron:before && cross-env ELECTRON_IS_DEV=1 electron .", + "electron": "yarn build:preload && yarn electron:before && electron .", "electron:no-delete-data": "yarn build:preload && electron .", "electron:start": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron\"", "electron:start:no-delete-data": "concurrently \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && yarn electron:no-delete-data\"", From e294bc3c8bbbc8f37373fb46ba680fd858647365 Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 13:46:23 +0800 Subject: [PATCH 09/10] fix(electron-forge): add app icon configuration for all platforms --- electron/main.js | 9 +++++++++ forge.config.js | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/electron/main.js b/electron/main.js index a6330fe4..6bfd83a1 100644 --- a/electron/main.js +++ b/electron/main.js @@ -418,6 +418,15 @@ const createMainWindow = () => { }; app.whenReady().then(() => { + // Set app name and dock icon for development mode on macOS + if (process.platform === 'darwin') { + app.setName('seedit'); + if (app.dock) { + const iconPath = path.join(dirname, '..', isDev ? 'public' : 'build', 'icon.png'); + app.dock.setIcon(iconPath); + } + } + createMainWindow(); app.on('activate', () => { diff --git a/forge.config.js b/forge.config.js index 51191ec1..74d87e2e 100644 --- a/forge.config.js +++ b/forge.config.js @@ -5,6 +5,7 @@ const config = { name: 'seedit', executableName: 'seedit', appBundleId: 'seedit.desktop', + icon: './public/icon', // electron-forge adds the correct extension per platform // NOTE: asar is disabled because of a bug where electron-packager silently fails // during asar creation with seedit's large node_modules. The app works fine without it. @@ -67,6 +68,7 @@ const config = { platforms: ['darwin'], config: { name: 'seedit', + icon: './public/icon.png', format: 'UDZO', }, }, @@ -80,6 +82,8 @@ const config = { platforms: ['win32'], config: { name: 'seedit', + setupIcon: './public/favicon.ico', + iconUrl: 'file://public/favicon.ico', }, }, // Linux @@ -88,6 +92,8 @@ const config = { platforms: ['linux'], config: { options: { + name: 'seedit', + icon: './public/icon.png', categories: ['Network'], }, }, From ca383365415e44365bf1be3a6dee1237f6cfd06b Mon Sep 17 00:00:00 2001 From: plebeius Date: Fri, 30 Jan 2026 14:01:38 +0800 Subject: [PATCH 10/10] fix(forge.config.js): remove malformed iconUrl from Squirrel config --- forge.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/forge.config.js b/forge.config.js index 74d87e2e..aec20908 100644 --- a/forge.config.js +++ b/forge.config.js @@ -83,7 +83,6 @@ const config = { config: { name: 'seedit', setupIcon: './public/favicon.ico', - iconUrl: 'file://public/favicon.ico', }, }, // Linux