Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion electron/before-pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down
27 changes: 12 additions & 15 deletions electron/build-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,49 @@ fi
node electron/download-ipfs || { echo "Error: failed script 'node electron/download-ipfs'" ; exit 1; }

dockerfile='
FROM electronuserland/builder:16
FROM node:22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docker build fails due to missing build tools

Medium Severity

The Docker base image changed from electronuserland/builder:16 to node:22. The electronuserland/builder image includes Wine, Mono, and other tools required for cross-platform Electron builds. The plain node:22 image lacks these dependencies, so the Docker-based Windows build (yarn electron:build:windows) will fail when run inside the container because Wine is required to create Windows installers on Linux using @electron-forge/maker-squirrel.

Additional Locations (1)

Fix in Cursor Fix in Web


# install node_modules
WORKDIR /usr/src/seedit
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
9 changes: 9 additions & 0 deletions electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
5 changes: 5 additions & 0 deletions forge.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -67,6 +68,7 @@ const config = {
platforms: ['darwin'],
config: {
name: 'seedit',
icon: './public/icon.png',
format: 'UDZO',
},
},
Expand All @@ -80,6 +82,7 @@ const config = {
platforms: ['win32'],
config: {
name: 'seedit',
setupIcon: './public/favicon.ico',
},
},
// Linux
Expand All @@ -88,6 +91,8 @@ const config = {
platforms: ['linux'],
config: {
options: {
name: 'seedit',
icon: './public/icon.png',
categories: ['Network'],
},
},
Expand Down
9 changes: 8 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
</script>
<script>
// Redirect non-hash URLs to hash URLs on initial load
if (window.location.pathname && window.location.pathname !== '/' && window.location.pathname !== '/index.html' && !window.location.hash) {
// Skip redirect for file:// protocol (Electron) or if pathname ends with index.html
if (
window.location.protocol !== 'file:' &&
window.location.pathname &&
window.location.pathname !== '/' &&
!window.location.pathname.endsWith('/index.html') &&
!window.location.hash
) {
window.location.replace('/#' + window.location.pathname + window.location.search);
}
</script>
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,20 @@
"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:no-delete-data": "yarn electron:before:delete-data && 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\"",
"electron:package": "yarn build && yarn build:preload && electron-forge package",
"electron:build": "yarn build && yarn build:preload && electron-forge make",
"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:before": "yarn electron-rebuild && yarn electron:before:delete-data",
"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: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}",
Expand Down Expand Up @@ -103,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",
Expand Down
143 changes: 0 additions & 143 deletions scripts/verify-executable.js

This file was deleted.

28 changes: 5 additions & 23 deletions src/components/error-display/error-display.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -46,30 +47,11 @@ const ErrorDisplay = ({ error }: { error: unknown }) => {
const { t } = useTranslation();
const [feedbackMessageKey, setFeedbackMessageKey] = useState<string | null>(null);
const errorDetails = getErrorDetails(error);
const feedbackTimeoutRef = useRef<ReturnType<typeof setTimeout> | 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;
Expand Down
Loading