new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Electron · Tutorial · all subjects

native modules

39 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Call destroy() on native addon before app quit

You must call destroy() on a native addon before the Electron app quits, ideally in the will-quit or before-quit event handler. Without this, persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit.

JavaScript wrapper for C++ native addon with EventEmitter

A wrapper class should extend EventEmitter to handle native events. It should load the addon using require('bindings') only on the target platform (e.g., Linux), forward events from C++ to JavaScript using this.emit(), provide clean methods to call into C++, include a destroy() method to release native resources, and parse JSON data into proper JavaScript objects including date conversion.

Platform-specific native addon loading pattern

Check process.platform at module load time to conditionally load the native addon. Throw an error if the module is loaded on an unsupported platform. Export an empty object {} on non-supported platforms so the module loads without error but provides no functionality.

Event forwarding from C++ addon to JavaScript

Listen to events from the C++ addon instance using addon.on(), then re-emit those events using this.emit() in the JavaScript wrapper. This allows JavaScript code to subscribe to native events with standard JavaScript event listeners.

Native addon JSON data parsing example

When receiving JSON payloads from C++, parse them with JSON.parse() and then convert special fields like dates from strings to JavaScript Date objects using new Date(). This example shows: const parsed = JSON.parse(payload); return { ...parsed, date: new Date(parsed.date) }

Building native Node.js addons

After configuring binding.gyp and writing C++/C code, run npm run build to compile the native addon. Once built successfully, the addon can be imported or required in the Electron application.

GTK3 compatible with Electron for native Linux UIs

GTK3 is compatible with Electron's Chromium runtime and can be used in native addons to create native Linux user interfaces. GTK3 GUI operations can run in their own thread and communicate back to JavaScript through events.

Complete C++ addon usage example in Electron

Example showing how to use a compiled C++ addon in an Electron process: import cppLinux from 'cpp-linux'; console.log(cppLinux.helloWorld('Hi!')); // Output: "Hello from C++! You said: Hi!"; cppLinux.on('todoAdded', (todo) => { console.log('New todo added:', todo); }); cppLinux.on('todoUpdated', (todo) => { console.log('Todo updated:', todo); }); cppLinux.on('todoDeleted', (todo) => { console.log('Todo deleted:', todo); }); cppLinux.helloGui();

Native addon todo application example

A complete C++ addon can implement a GTK3 GUI with: a text entry field for todo items, a calendar widget for selecting dates, an Add button to create new todos, a scrollable list showing all todos, and right-click context menus for editing and deleting todos. User interactions trigger JavaScript events allowing real-time response.

Phase Three success criteria

Phase Three is complete when `node script/node-spec-runner.js --default` exits with zero failures and all changes are committed per the commit guidelines. Do not stop until these criteria are met.

When to edit patches

During active `git am` conflict: fix in node repo, then run `git am --continue`. Modifying patch outside conflict: edit `.patch` file directly. Creating new patch (rare, avoid): commit in node repo, then run `e patches node`. Fix existing patches 99% of the time rather than creating new ones.

Node.js upgrade workflow has three phases

Phase One: Run `e sync --3` repeatedly, fixing patch conflicts as they arise, until it succeeds, then export patches and commit changes. Phase Two: Run `e build -k 999 -- --quiet` repeatedly, fixing build issues, until it succeeds, then run `e start --version` to validate Electron launches, and commit changes. Phase Three: Run `node script/node-spec-runner.js --default`, fix failing tests, and commit fixes until all tests pass.

Patch system mental model

Patches flow: `patches/node/*.patch` → `[e sync --3]` → `../third_party/electron_node` commits. Commits flow back: `../third_party/electron_node` commits → `[e patches]` → `patches/node/*.patch`.

Do not delete patches unless 100% certain they are no longer needed

Never delete or skip patches without verification. For major version upgrades, patches that shim deprecated V8 APIs or backport upstream changes are often deletable because the new Node.js version already incorporates them—but verify before removing. Complicated conflicts or hard to resolve issues should be presented to the user after exhausting all other options. Do not delete a patch just because you cannot solve it.

Never use git am --skip to recreate patches

Never use `git am --skip` and then manually recreate a patch by making a new commit. This destroys the original patch's authorship, commit message, and position in the series. If `git am --continue` reports 'No changes', investigate why—the changes were likely absorbed by a prior conflict resolution's 3-way merge. Present this situation to the user rather than skipping and recreating.

Clear rerere cache before starting an upgrade session

Run `git rerere clear` in both the electron and `../third_party/electron_node` repos at the start of each upgrade session. Stale recorded resolutions from a prior attempt can silently apply wrong merges.

Ensure pre-commit hooks are installed before upgrade

Check that `.git/hooks/pre-commit` exists in the electron repo. If not, run `yarn husky` to install it. The hook runs `lint-staged` which handles clang-format for C++ files.

Phase One workflow steps

1. Run `e sync --3` (the `--3` flag enables 3-way merge, always required). 2. If succeeds, skip to step 5. 3. If patch fails: identify target repo and patch from error output, analyze failure, fix conflict in `../third_party/electron_node` working directory, run `git am --continue` in `../third_party/electron_node`, repeat until all patches for that repo apply. IMPORTANT: Once `git am --continue` succeeds you MUST run `e patches node` to export fixes. Return to step 1. 4. When `e sync --3` succeeds, run `e patches all`. 5. Read `references/phase-one-commit-guidelines.md` NOW, then commit changes following those instructions exactly.

Phase One success criteria

Phase One is complete when `e sync --3` exits with code 0 (no patch failures) and all changes are committed per the commit guidelines. Do not stop until these criteria are met.

Phase Two workflow steps

1. Run `e build -k 999 -- --quiet` (the `--quiet` flag suppresses per-target status lines, showing only errors and the final result). 2. If succeeds, skip to step 6. 3. If build fails: identify underlying file in 'electron' from the compilation error message, analyze failure, fix build issue by adapting Electron's code for the change in Node.js, run `e build -t {target_that_failed}.o` to build just the failed target. The target name can be identified from the failure line in the build log. 4. Read `references/phase-two-commit-guidelines.md` NOW, then commit changes following those instructions exactly. 5. After ANY commit (especially patch commits), immediately run `git status` in the electron repo. Look for other modified `.patch` files that only have index/hunk header changes. These are dependent patches affected by your fix. Commit them immediately with: `git commit -am "chore: update patches (trivial only)"`. Return to step 1. 6. When `e build` succeeds, run `e start --version`. 7. Check if you have any pending changes in the Node.js repo by running `git status` in `../third_party/electron_node`. If you have changes follow the instructions for patch fixes.

Phase Two success criteria

Phase Two is complete when `e build -k 999 -- --quiet` exits with code 0 (no build failures), `e start --version` has been run to check Electron launches, and all changes are committed per the commit guidelines. Do not stop until these criteria are met. Do not delete code or features, never comment out code in order to take short cut. Make all existing code, logic and intention work.

Phase Two patch fixes workflow

When the error is in a file that Electron patches (check with `grep -l "filename" patches/node/*.patch`): 1. Edit the file in the Node.js source tree (`../third_party/electron_node/...`). 2. Create a fixup commit targeting the original patch commit: `cd ../third_party/electron_node`, `git add <modified-file>`, `git commit --fixup=<original-patch-commit-hash>`, `GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i <commit>^`. 3. Export the updated patch: `e patches node`. 4. Commit the updated patch file following `references/phase-one-commit-guidelines.md`. To find the original patch commit to fixup: `git log --oneline | grep -i "keyword from patch name"`. The base commit for rebase is the Node.js commit before patches were applied. Find it by checking the `refs/patches/upstream-head` ref.

Phase Two Electron code fixes

When the error is in Electron's own source code (files in shell/, electron/, etc.): 1. Edit files directly in the electron repo. 2. Commit directly (no patch export needed).

Phase Three workflow steps

1. Run `node script/node-spec-runner.js --default` from the electron repo. 2. If all tests pass, Phase Three is complete. 3. If tests fail: identify the failing test file(s) from the output, analyze each failure, fix the test in `../third_party/electron_node/test/...`, re-run the specific failing test to verify: `node script/node-spec-runner.js {test-path}`. The test path is relative to the node `test/` directory, e.g. `test/parallel/test-crypto-key-objects-raw.js`. Do NOT use `--default` when running specific tests. Do NOT run tests directly with `ELECTRON_RUN_AS_NODE`—the runner handles environment setup. Commit the fix using the fixup workflow and commit guidelines. Return to step 1.

BoringSSL incompatibilities in Node.js test suite

Electron builds Node.js against Chromium's BoringSSL instead of Node.js's bundled OpenSSL. Upstream Node.js now supports building against BoringSSL natively (enabled via `node_openssl_path = "//third_party/boringssl"` in `build/args/all.gn`), so most of Electron's historical BoringSSL workarounds have been eliminated. Expect to delete these workarounds over time rather than grow them. Only add a guard when a feature is genuinely still missing from BoringSSL; upstream tests increasingly self-skip when `process.features.openssl_is_boringssl` is set, so no Electron change is needed.

Preferred guard for BoringSSL-unsupported features

Skip the whole test file at the top and add it to `fix_crypto_tests_to_run_with_bssl.patch` using this pattern: `if (process.features.openssl_is_boringssl) { common.skip('Skipping unsupported feature tests'); }`. For tests that cannot be cleanly guarded inline, add the whole file to `script/node-disabled-tests.json` instead.

BoringSSL unsupported features as of v24.18.0

The following features are still unsupported in Chromium's BoringSSL as of v24.18.0: RSA-PSS keygen (deprecation path, file-level `common.skip` in `test-crypto-keygen-deprecation`), ML-DSA keys (file-level `common.skip` in `test-crypto-pqc-key-objects-ml-dsa`), ML-KEM keys (disabled in `node-disabled-tests.json` in `test-crypto-pqc-key-objects-ml-kem`), FIPS mode (disabled in `test-crypto-fips`), Secure heap (disabled in `test-crypto-secure-heap`), Stateless DH (disabled in `test-crypto-dh-stateless`), Assorted keygen / WebCrypto keygen (disabled in `test-crypto-keygen`, `test-webcrypto-keygen`, `wpt/test-webcrypto`).

BoringSSL behavioral differences from OpenSSL

Some errors in BoringSSL just changed shape compared to OpenSSL and require assertion updates rather than test skips. For example, creating a private key from an unsupported OKP (Ed448) JWK now throws `Invalid JWK OKP key` (previously `Invalid JWK data`); see nodejs/node#62499. Electron's `spec/node-spec.ts` assertion was loosened to `/Invalid JWK/`. When guarding a test, prefer a precise capability check (e.g. `ciphers.includes('aes-128-ccm')`) over a blanket `process.features.openssl_is_boringssl` check where the feature can be probed directly.

Snapshot test regeneration for V8 differences

Some tests compare output against committed `.snapshot` files using `assert.strictEqual`—these are NOT wildcard comparisons. When Chromium's V8 produces different output (e.g. different stack traces due to V8 enhancements), the snapshot must be regenerated: `NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs`. Then inspect the diff to verify the changes are expected, and commit the updated snapshot into the appropriate patch.

Phase Three patch fixes workflow

Most test fixes go into existing patches in `patches/node/`. Use the fixup workflow: 1. Edit the test file in `../third_party/electron_node/test/...`. 2. Find the relevant patch commit: `git log --oneline | grep -i "keyword"`. Crypto/BoringSSL tests → `fix crypto tests to run with bssl`. Snapshot tests → the specific snapshot patch (e.g. `test: accomodate V8 thenable`). Flaky tests → `test: formally mark some tests as flaky`. 3. Create a fixup commit: `cd ../third_party/electron_node`, `git add test/path/to/test.js`, `git commit --fixup=<patch-commit-hash>`, `GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i <commit>^`. 4. Export: `e patches node`. 5. Read `references/phase-three-commit-guidelines.md` NOW, then commit the updated patch file.

When to add tests to disabled tests list

Only add a test to `script/node-disabled-tests.json` as a last resort—when the test is fundamentally incompatible with Electron's architecture (not just a BoringSSL difference that can be guarded). Tests disabled here are completely skipped and never run.

High-churn patches requiring work during Node.js upgrades

`fix_handle_boringssl_and_openssl_incompatibilities.patch` — Electron uses BoringSSL (via Chromium) while Node.js expects OpenSSL. Historically large and complex, this patch was greatly reduced once Node.js gained native BoringSSL support. It still shims some C++-level differences, and upstream OpenSSL/ncrypto API changes can break it. `fix_crypto_tests_to_run_with_bssl.patch` — Companion to the above; adapts Node.js crypto tests for BoringSSL. Also greatly reduced now that upstream tests self-skip under BoringSSL. `support_v8_sandboxed_pointers.patch` — V8 sandbox pointer support requires careful adaptation when V8 APIs change. `build_add_gn_build_files.patch` — The GN build file patch is large and touches many build targets. Upstream build system changes frequently conflict.

Major Node.js version upgrade expectations

Major Node.js version transitions (e.g., v22 → v24) are significantly more involved than patch bumps. Expect patch deletions—Electron uses Chromium's V8, which is often ahead of the V8 version bundled in Node.js. Many patches exist to bridge this gap. When Node.js bumps to a newer major version, its V8 catches up to Chromium's, and those bridge patches can be deleted. In the v22 → v24 upgrade, 17 patches were deleted for this reason. Update `@types/node` in `package.json` to match the new major version. Post-upgrade regressions are expected. Even after the upgrade lands, follow-up fix PRs for edge cases (ESM path handling, certificate loading, platform-specific issues) are normal.

Node.js version bump versus major upgrade types

There are two types of Node.js version updates. Bumps (patch/minor) are automated by `electron-roller[bot]` with commit title `chore: bump node to v{version}`. Trivial patch index updates are handled automatically by `patchup[bot]`. These often land cleanly but may require manual patch fixes. Major upgrades (e.g., v22 → v24) are manual, large PRs with commit title `chore: upgrade Node.js to v{X}.{Y}.{Z}`. These typically involve deleting obsolete patches, adapting many others, and updating `@types/node` in `package.json`.

Key directories for Node.js upgrade work

Current directory: Electron repo (always run `e` commands here). `../third_party/electron_node`: Node.js repo (where patches apply). `patches/node/`: Patch files for Node.js. `docs/development/patches.md`: Patch system documentation.

Patch fixing rules

1. Preserve authorship: Keep original author in TODO comments (from patch `From:` field). 2. Never change TODO assignees: `TODO(name)` must retain original name. 3. Update descriptions: If upstream changed APIs or macros, update patch commit message to reflect current state. 4. Never skip-and-recreate a patch: If `git am --continue` says 'No changes — did you forget to use git add?', do NOT run `git am --skip` and create a replacement commit.

Commands for Node.js upgrade workflow

`e sync --3` — Clone deps and apply patches with 3-way merge. `git am --continue` — Continue after resolving conflict (run in node repo). `e patches node` — Export commits from node repo to patch files. `e patches all` — Export all patches from all targets. `e patches node --commit-updates` — Export patches and auto-commit trivial changes. `e patches --list-targets` — List targets and config paths. `e build -k 999 -- --quiet` — Build Electron, continue on errors, suppress status lines. `e build -t {target}.o` — Build just one specific target to verify a fix. `e start --version` — Validate Electron launches after successful build. `node script/node-spec-runner.js --default` — Run full Node.js test suite. `node script/node-spec-runner.js test/parallel/test-foo.js` — Run a single test. `NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs` — Regenerate snapshot for a snapshot-based test.

Key directories for Phase Two and Phase Three work

Current directory: Electron repo (always run `e` commands here). `../third_party/electron_node`: Node.js repo (do not touch this code to fix build issues, just read it to obtain context). `script/node-spec-runner.js` — Test runner script. `script/node-disabled-tests.json` — Permanently disabled tests (do not try to fix these). `../third_party/electron_node/test/` — Node.js test files (where patches apply). `patches/node/fix_crypto_tests_to_run_with_bssl.patch` — BoringSSL crypto test adaptations. `patches/node/test_formally_mark_some_tests_as_flaky.patch` — Flaky test list.

LanguageModelCloneOptions signal parameter

LanguageModelCloneOptions accepts a signal parameter of type AbortSignal, which allows cancellation of language model clone operations.

Give your agent this brain