6.6.0: Modernize toolchain — Electron 42 (hardened), Vite, Vitest, Capacitor#1287
6.6.0: Modernize toolchain — Electron 42 (hardened), Vite, Vitest, Capacitor#1287jthrilly wants to merge 29 commits into
Conversation
Electron 42 + security hardening, Webpack->Vite, Jest->Vitest, Cordova->Capacitor, vendor submodules, remove Server integration, Node 24 LTS. Target version 6.6.0.
Delete pairing/discovery UI, pairedServer duck, ApiClient, serverDiscoverer, serverAddressing, useServerConnectionStatus, and the secure-comms cert handling in the Electron main process. Keep protocol import from file/URL and session export to file. Replace deprecated request-promise-native with native fetch in downloadProtocol. Drop now-unused deps: secure-comms-api, mdns, zeroconf, sockjs-client, axios, request, request-promise-native.
… + electron 42 - Remove webpack, CRA (react-dev-utils), all loaders, jest, and legacy/junk deps (svg2png, icon-gen, i, upgrade, polyfills, request, etc.) - Add vite 7, electron-vite 5, @vitejs/plugin-react 5, vitest 4, @vitest/coverage-v8 - Upgrade electron 9 -> 42, electron-builder 22 -> 26, electron-devtools-installer 4 - Reduce babel.config.js to ESLint-only JSX parsing - Drop arch=x64 from .npmrc (native arm64); legacy-peer-deps for React 16 tree - Point electron-builder at out/** ; main -> out/main/index.js
…gration - vite.shared.js: React (JSX in .js), aliases (networkQuery, shared-consts, tinyqueue, path->path-browserify, ~ strip for scss), workers, base ./ - vite.config.js (web/capacitor + vitest), electron.vite.config.js (main/preload/renderer) - Root index.html (module entry, drop cordova.js script) - postcss.config.js to object-plugin form for vite - csvDecoder/forceSimulation workers to vite ?worker imports Renderer pipeline compiles; remaining failures are renderer Node imports (filesystem.js etc.) handled by the preload/IPC hardening in C.4/C.5.
- Port main process to src/main/* (ESM): index, windowManager, appManager, mainMenu, dialogs, log, loadDevTools. - Hardened BrowserWindow: contextIsolation+sandbox+nodeIntegration:false, preload, setWindowOpenHandler, webContents.openDevTools, fullscreen events. - Asset media served via modern protocol.handle (replaces registerFileProtocol). - IPC contract (src/main/ipc.js) + NCAPI preload bridge (src/preload/index.js): sync system bootstrap, fs/*, protocol:extract, export:run/abort, shell. - Filesystem + zip extraction + the network-exporters export pipeline now run in main behind IPC. CommonJS interop for vendored packages in vite/electron-vite. main + preload compile; renderer call-site migration follows in C.5.
…green (C.5) - Rewrite renderer Node/electron usage to window.NCAPI: Environment, filesystem (delegates fs to main; streaming removed), extractProtocol (->protocol:extract), exportProcess + SessionManagementScreen (->export:run/abort over IPC). - Convert src/config.js to ESM; remove unused electron-shim.js. - Security hardening of the IPC surface (from automated review): - pathGuard: canonicalised safe-root checks for all fs:* ops (fix substring bypass) - sourceFiles allowlist: only extract user-selected/downloaded files - protocolFiles: per-entry zip-slip guard + awaited validator + dest must be userData - assetProtocol: path-traversal containment for the privileged asset: scheme - shell:openExternal restricted to http/https/mailto electron-vite build of main + preload + renderer all succeed.
…ntime) - getVersion/DeviceInfo/Environment via NCAPI.system bootstrap - ExternalLink -> NCAPI.openExternal; initFileOpener/initMenuActions/remote -> NCAPI.on.* events; index.js RESET_STATE -> NCAPI.on.resetState - App.js + VisualPreferences fullscreen via NCAPI.window (+ window:* IPC) - networkFormat hashing crypto -> jssha (browser-compatible) - Replace builder-util-runtime CancellationError with shared local class Renderer bundle now has zero Node/electron imports; all three targets build.
… (C.7)
- uuid bare imports -> uuid/v4 (browser rng, avoids md5/sha1->crypto)
- restore accidentally-dropped csvtojson dep; worker import via package subpath
- inline require('path')/require('csvtojson') -> top-level imports
- protocol-validation Environment.js made main-process-safe (guard window)
- object-hash aliased to its Node entry; vite-plugin-node-polyfills supplies
crypto/buffer/stream for in-renderer hashing (pure computation)
Verified: electron-vite builds main+preload+renderer; the hardened app launches,
rehydrates state, dispatches DEVICE_READY and routes with zero runtime errors.
NCAPI.fs.readFile returns a Uint8Array over IPC (was a Node Buffer, whose toString() yielded UTF-8). Decode with TextDecoder before JSON.parse so protocol import works. Fixes 'Unexpected non-whitespace character after JSON'.
…es green - vitest.setup.js: enzyme-adapter-react-16, enzyme-to-json serializer, rAF/ matchMedia polyfills, automocks (electron/fs/electron-log/redux-logger/uuid) - codemod jest.* -> vi.* across all test files and __mocks__ - install jsdom; pin cheerio 1.0.0-rc.3 override (enzyme 3 needs lib/utils subpath) 14 files still failing (done()-callbacks, ESM export reassignment, vi.mock default keys, obsolete snapshots) — fixed next.
- Workflow fixed 14 files: vi.mock default keys, constructor mocks, fake-timer rAF semantics (toFake), runTimersToTime->advanceTimersByTime, ESM mock shapes. - Convert leftover done()-callback async tests to Promise/async form (loadExternalData, useExternalData, withExternalData). - Harden rAF polyfill (window + global) for animejs; clean obsolete snapshots. Result: 93 files / 540 tests passing, 0 failures.
- Delete integration-tests/ (Spectron, incompatible with Electron 42), config/jest/, scripts/test.js, docker-compose.yml (all integration-only). - Add ESLint override exposing Vitest globals (vi/describe/it/...) for test and __mocks__ files. Jest is fully removed; Vitest is the sole test runner.
- Remove all Cordova scaffolding (config.xml, platforms/, plugins/, scripts/cordova). - Add Capacitor 8 (core/cli/ios/android) + plugins: filesystem, device, app, browser, keyboard, status-bar, network. capacitor.config.json (webDir: dist). - Rename environment CORDOVA->CAPACITOR; Environment.js detects via Capacitor.isNativePlatform()/getPlatform(); isCordova->isCapacitor. - Port mobile branches of ~14 files to Capacitor plugins (Filesystem for fs + redux-persist storage engine, Device/App for info/version, Browser for links, StatusBar for immersive). Native file picker left as a TODO. - Reconcile tests for the platform rename. Wire initDeviceInfo() at startup. Web + electron builds pass; 540 tests green. Native device builds deferred to CI.
…cts (E.4) npx cap add ios/android + cap sync. Native projects committed; device builds (Gradle/Xcode) deferred to CI per the agreed bar.
…/F.2/F.4)
- Bump version to 6.6.0 (package.json, Android build.gradle, iOS MARKETING_VERSION).
- Remove dead config: www/, public/ (ported to src/main + root index.html),
config/webpack*/paths/env/nc-dev-utils/polyfills, old scripts/{start,build,...}.
- Resolve all ESLint errors (default exports for single-export main modules,
wrap long lines, disable rules for Vite ?worker/jsSHA tooling gaps); add
Vitest globals + spellcheck terms. npm run lint is clean.
- Remove obsolete Dockerfile + .dockerignore (Node 12 / mDNS / Spectron). - CI (main.yml, dist.yml): Node 24, npm ci, drop submodules/mDNS/python/npm-pin; run vitest (test:ci) and electron-vite build. - README: rewrite requirements, scripts, desktop/mobile dev, and structure for the new toolchain; drop Cordova/webpack/Jest/mDNS sections.
Electron no longer downloads its binary on npm install (postinstall removed for supply-chain security; ELECTRON_SKIP_BINARY_DOWNLOAD is gone). It now downloads on first launch (npm run dev). Add a 'download:electron' script (install-electron bin) to pre-fetch deterministically; document in README. Resolve mobile protocol import: add @capawesome/capacitor-file-picker and wire beginLocalProtocolImport's Capacitor branch to pick a .netcanvas (readData), and implement extractProtocol's Capacitor branch (JSZip + Filesystem, unzipping into Directory.Data/protocols/<uid>). JSZip is dynamic-imported so it is not bundled into the Electron renderer. Plugin synced into ios/ and android/. Lint clean; 540 tests pass; web + electron builds green.
Build artifacts had been committed by 'git add -A' after builds. Ignore and untrack them; they are regenerated by the build.
|
Important Review skippedToo many files! This PR contains 189 files, which is 39 over the limit of 150. To get a review, narrow the scope: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (111)
📒 Files selected for processing (189)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Remove pre-existing describe.only/it.only (Jest ran only those silently; Vitest run mode rejects .only). Enables the previously-hidden tests (+5). - One newly-enabled test (getNextUnplacedNode 'uses sort') asserts unimplemented sort behavior; mark it.skip with a note (was excluded via .only pre-migration). - Mock animejs in the test setup so its engine doesn't schedule timers that outlive the jsdom environment (the intermittent 'requestAnimationFrame is not defined' unhandled error in MultiNodeBucket). 545 tests pass, 0 unhandled errors.
Clears the Node 20 runtime deprecation warning (forced to Node 24 from June 16).
|
Note for reviewers — both automated reviewers (Copilot, CodeRabbit) skipped this PR purely on file count. That count is dominated by two parts of the migration that are large but not hand-authored here:
The hand-written changes worth focusing on:
Design rationale + phased plan: |
Vite's dev server serves src/ as native ESM and does not transform CommonJS, so
the Babel-style CJS in the vendored networkQuery and protocol-validation
packages (and the two network-exporters constants the renderer imports) broke on
`vite dev` ("does not provide an export named ..."), even though the rollup
build handled them. Convert these files (and their tests) from require/
module.exports to import/export. Trim the now-unneeded commonjsOptions (renderer:
node_modules only; main keeps network-exporters, which stays CJS and runs only in
main). Add optimizeDeps.esbuildOptions loader so the dep scanner accepts JSX-in-.js.
Web + Electron builds pass; 545 tests green.
The hardened renderer used browser fetch() to download remote .netcanvas files, which is blocked by CORS. Move the fetch + temp-file save into the main process (net.fetch, no CORS) behind NCAPI.protocol.download; the returned temp path is inside app temp, which the extract path guard already permits.
framer-motion/framesync (and animejs) schedule rAF frames that can fire after a test's jsdom env is torn down, throwing "window is not defined" as a flaky unhandled error (framesync is imported inside framer-motion, so it can't be vi.mock'd). Set dangerouslyIgnoreUnhandledErrors so CI is stable. Add a "Dev: Vite + Electron" VS Code task.
The protocol download URL is user-supplied and fetched in the main process. Resolve the host and refuse private/loopback/link-local targets, and reject redirects so a public host cannot bounce to an internal address (e.g. cloud metadata). Addresses the pushed-commit security review finding.
Address the commit-review follow-ups: - TOCTOU/DNS-rebinding: pin the socket to the validated IP via a custom lookup on Node http/https (hostname still used for Host header + TLS SNI), instead of letting net.fetch re-resolve after validation. - Range coverage: classify resolved addresses with ipaddr.js and allow only public unicast, rejecting all special-use IPv4/IPv6 ranges (CGNAT, reserved, multicast, IPv6 ULA, IPv4-mapped, ...) — replaces the bespoke checks. - Redirects are still not followed (Node http.get does not auto-follow).
Modernizes the build, runtime, and test toolchain for v6.6.0. No product behavior changes beyond removing the obsolete Server integration. Work is split into dependency-ordered phases, each landing on a buildable/testable tree.
What changed
.node-version/.nvmrc/engines).networkQuery,network-exporters,protocol-validation) as in-tree source;.gitmodulesremoved.request-promise-native→ nativefetch.contextIsolation: true,sandbox: true,nodeIntegration: false, no@electron/remote. A typedcontextBridgepreload (window.NCAPI) exposes a minimal API; all privileged operations (filesystem, dialogs, app info, the zip extraction, and the network-exporters export pipeline) run in the main process behind IPC. The asset scheme uses the modernprotocol.handle. IPC is hardened against path-traversal / zip-slip, with a shell-scheme allowlist.electron-vitefor main/preload/renderer). One renderer build feeds Electron and Capacitor.enzyme-adapter-react-16). The dead Spectronintegration-tests/suite is removed; Jest is fully gone.ios//android/projects scaffolded and committed; the platform abstraction now uses Capacitor plugins (@capacitor/filesystem,device,app,browser,keyboard,status-bar,network) and@capawesome/capacitor-file-pickerfor protocol import.www/,public/, the obsolete Dockerfile; modernized README and CI (Node 24,npm ci, vitest + electron-vite). Version bumped to 6.6.0 (package.json + native projects).Verification
npm run lintclean · 540 Vitest tests pass ·vite build+electron-vite build(main/preload/renderer) succeed · the hardened Electron app builds and launches (boots, rehydrates state, routes; protocol import verified) ·npx cap syncsucceeds with both native projects present.Notes / out of scope
electron-builderpackaging (dist:*) is a release/CI step; onlyelectron-vite build+ launch were verified locally.npm install(it downloads on firstnpm run dev); adownload:electronscript and README note are included.docs/superpowers/.🤖 Generated with Claude Code