Skip to content

fix: support ESM app entrypoints in the universal shim#210

Open
claude[bot] wants to merge 8 commits into
mainfrom
fix/esm-asar-entrypoint
Open

fix: support ESM app entrypoints in the universal shim#210
claude[bot] wants to merge 8 commits into
mainfrom
fix/esm-asar-entrypoint

Conversation

@claude

@claude claude Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Requested by Samuel Attard · Slack thread

Before / After

Before: building a universal binary from an Electron app whose main-process entrypoint is ESM (a .mjs entry, or "type": "module") crashed at launch with ERR_REQUIRE_ESM whenever the x64 and arm64 ASARs diverged. The generated outer app.asar shim does require() of the per-arch ASAR, and require() can't load an ESM entrypoint. (#90)

After: when both arches' entrypoints are ESM, the shim is emitted as an ESM module that uses dynamic import() instead, so ESM apps launch correctly. CommonJS apps are unchanged.

Safety guard

We only ship the ESM shim when we've positively confirmed the entrypoint's module format. Format is read from each ASAR's own package.json using Node's rules (.mjs/.cjs extension wins; otherwise the "type" field decides), and anything we can't positively identify as ESM is treated as CommonJS — so we never switch on a guess. Both arches must agree: if one arch is ESM and the other CommonJS, we throw a clear error rather than ship a binary that would crash on one of them.

How

  • src/asar-utils.ts: new detectEntrypointModule(packageJson) and resolveShimModule(x64, arm64) helpers.
  • src/index.ts: both shim copy sites now read each arch's package.json (NO_ASAR from disk, HAS_ASAR via asar.extractFile), resolve the module, and on a confirmed ESM verdict copy entry-asar/esm/{has,no}-asar.mjsindex.mjs and set pj.main = 'index.mjs'; otherwise the existing .js/index.js path is unchanged.
  • New ESM shims in entry-asar/esm/ use createRequire + top-level await import(pathToFileURL(process._archPath).href), compiled by a dedicated entry-asar/esm/tsconfig.json (nodenext/es2022) added as a third tsc build pass.

Tests

  • New test/detect-entrypoint.spec.ts: 16 unit tests covering the detection matrix and the divergence guard (written first, TDD).
  • New integration tests in test/index.spec.ts (HAS_ASAR + NO_ASAR ESM shim) with ESM fixtures generated in test/globalSetup.ts. These exercise on macOS CI (require lipo/clang/arch).

Closes #90.


Generated by Claude Code

When the x64 and arm64 app.asar (or app dir) contents diverge, the
generated entry shim used `require()` to load the per-arch archive. If
the inner app's entrypoint is an ES module this throws ERR_REQUIRE_ESM
at launch.

Detect each arch's entrypoint module format from its package.json and,
only when both arches agree on ESM, ship an ESM shim that uses dynamic
import. If the two arches disagree on module system, fail the build with
a clear error instead of producing a broken bundle.

- Add detectEntrypointModule / resolveShimModule to asar-utils
- Add ESM shim sources entry-asar/esm/{has,no}-asar.mts compiled to .mjs
- Wire both the HAS_ASAR and NO_ASAR shim sites in makeUniversalApp
- Add unit tests for the detection logic and ESM integration tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPgSb3xj4vdi1mUNSzpVUD
@MarshallOfSound MarshallOfSound marked this pull request as ready for review June 28, 2026 17:32
@MarshallOfSound MarshallOfSound requested a review from a team as a code owner June 28, 2026 17:32
claude Bot added 6 commits June 28, 2026 17:43
The no-asar ESM fixtures are copied straight into the bundle tree, so
diverging via a loose plain `extra-file.txt` was classified as a unique
PLAIN file and tripped makeUniversalApp's mach-o parity guard. Diverge
via uniquely-named `.bin` files instead (classified as V8 snapshots and
excluded from the parity check), exactly the way the existing non-ESM
`should shim two different app folders` test does.
The heavy verifyApp integration tests run ~60s each on their own and the
suite is contended under maxConcurrency, so 80s left too little margin
and one test timed out at ~140s. Raise VERIFY_APP_TIMEOUT to 180s.
@socket-security

socket-security Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedelectron@​28.3.3946010098100

View full report

@socket-security

socket-security Bot commented Jun 28, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
High CVE: Electron: Use-after-free in offscreen child window paint callback

CVE: GHSA-532v-xpq5-8h95 Electron: Use-after-free in offscreen child window paint callback (HIGH)

Affected versions: < 39.8.1; >= 40.0.0-alpha.1 < 40.7.0; >= 41.0.0-alpha.1 < 41.0.0

Patched version: 39.8.1

From: package.jsonnpm/electron@28.3.3

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/electron@28.3.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: Electron: Use-after-free in WebContents fullscreen, pointer-lock, and keyboard-lock permission callbacks

CVE: GHSA-8337-3p73-46f4 Electron: Use-after-free in WebContents fullscreen, pointer-lock, and keyboard-lock permission callbacks (HIGH)

Affected versions: < 38.8.6; >= 39.0.0-alpha.1 < 39.8.0; >= 40.0.0-alpha.1 < 40.7.0; >= 41.0.0-alpha.1 < 41.0.0-beta.8

Patched version: 38.8.6

From: package.jsonnpm/electron@28.3.3

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/electron@28.3.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: Electron: Renderer command-line switch injection via undocumented commandLineSwitches webPreference

CVE: GHSA-9wfr-w7mm-pc7f Electron: Renderer command-line switch injection via undocumented commandLineSwitches webPreference (HIGH)

Affected versions: < 38.8.6; >= 39.0.0-alpha.1 < 39.8.0; >= 40.0.0-alpha.1 < 40.7.0; >= 41.0.0-alpha.1 < 41.0.0-beta.8

Patched version: 38.8.6

From: package.jsonnpm/electron@28.3.3

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/electron@28.3.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
High CVE: Electron: Use-after-free in PowerMonitor on Windows and macOS

CVE: GHSA-jjp3-mq3x-295m Electron: Use-after-free in PowerMonitor on Windows and macOS (HIGH)

Affected versions: < 38.8.6; >= 39.0.0-alpha.1 < 39.8.1; >= 40.0.0-alpha.1 < 40.8.0; >= 41.0.0-alpha.1 < 41.0.0-beta.8

Patched version: 38.8.6

From: package.jsonnpm/electron@28.3.3

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/electron@28.3.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Deprecated by its maintainer: npm boolean

Reason: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

From: ?npm/electron@28.3.3npm/boolean@3.2.0

ℹ Read more on: This package | This alert | What is a deprecated package?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/boolean@3.2.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App entrypoint fails to load for ESM app if arm64 and x64 apps don't match

2 participants