[PR #877] [MERGED] fix(javascript): keep XHR and client endpoints that receiver spellings hid #2313

Closed
opened 2026-10-16 21:17:08 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/877
Author: @kaoru0822-kitauji
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/7/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/javascript-computed-xhr-method


📝 Commits (4)

  • 602d002 fix(javascript): keep computed-method XHR request URLs
  • ae849a7 fix(javascript): never read window or document open as XHR
  • e3e7664 fix(javascript): keep literal-method and URL-literal requests on aliased receivers
  • e32028d fix(javascript): keep bare relative URLs for computed-method XHR

📊 Changes

2 files changed (+112 additions, -22 deletions)

View changed files

📝 src/domain/javascriptStaticAnalysisHelpers.ts (+87 -21)
📝 src/domain/webBundleAnalyzer.test.ts (+25 -1)

📄 Description

Summary

Follow-up to #872 and #874, both merged. It restores endpoints that their receiver-spelling heuristics could drop, as flagged in Codex review:

  1. Computed-method XHR (#872 was merged at its first commit, before the review fix):
    xhr.open(method, "/dynamic-method"); // endpoint on 4.1.0, none on main since #872
    
    With a computed method, the second literal is now kept as the URL unless it is provably not one: a Node fs.open flag (r, r+, w+, ax, …), a reserved browsing-context name (_blank/_self/_parent/_top), or a call on a receiver spelled as a browsing context or document (see 2). Bare relative URLs such as xhr.open(method, "api/users") are therefore kept.
  2. Literal methods on any receiver: parent.open("GET", "/api") and self.open("post", "/x") may be local XHR bindings. A literal HTTP method is read as XHR whatever the receiver is called. The browsing-context and document exclusion (window/self/globalThis/top/parent/opener/frames/document.open) applies only when the method is computed. window.open(url, "/preview") is therefore not an endpoint, while parent.open("GET", "/api") is.
  3. URL literals on collection-spelled receivers (#874): isKeyedCollectionReceiver checks spellings, not bindings. A get/delete literal that is a URL or path therefore stays an endpoint, as in new Headers().get("/users") with an imported Headers, api.headers.get("https://…"), and api.searchParams.delete("../search"). Only non-URL keys on such receivers are skipped, for example response.headers.get("content-type") and new URLSearchParams(s).get("q").

Unchanged: fs.open(path, "r") and window.open(url, "_blank") produce no endpoint.

Residual ambiguity: without binding resolution, popup.open(url, "preview") (computed method, non-keyword target name, aliased receiver) has the same syntax as an aliased xhr.open(method, "api/users"). It is still reported, as it was on 4.1.0.

No schema or catalog change.

Verification

  • src/domain/webBundleAnalyzer.test.ts parity cases cover every example above. The open case expects /dynamic-method, /parent-xhr, /self-xhr, and api/relative and excludes /preview, ./frame, /replace, r, w+, _blank, and _TOP. The keyed-collection case expects /users, https://api.example.test/headers, and ../search and still excludes q/content-type/page/map-key. Both fail on main.
  • npm run check:changed (37 files, 749 tests) passes. npm run test:focused on the JavaScript/Electron/web-bundle boundary and acceptance tests (63 files) also passes. It excludes the two V8 Inspector runtime files, which fail identically on unmodified main on this host.

No Hopper/Ghidra/IDA verification is needed.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/877 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/7/2026 **Status:** ✅ Merged **Merged:** 10/7/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/javascript-computed-xhr-method` --- ### 📝 Commits (4) - [`602d002`](https://github.com/morluto/rea/commit/602d0021d45a6cdab9f806554f3ee12ea670ec97) fix(javascript): keep computed-method XHR request URLs - [`ae849a7`](https://github.com/morluto/rea/commit/ae849a72811857ba9755962ec48a1d76c9d1181a) fix(javascript): never read window or document open as XHR - [`e3e7664`](https://github.com/morluto/rea/commit/e3e76646657e950e24241ba715eb97ea385933e9) fix(javascript): keep literal-method and URL-literal requests on aliased receivers - [`e32028d`](https://github.com/morluto/rea/commit/e32028d1b566872ba8cd08fc6800c198d6aef30b) fix(javascript): keep bare relative URLs for computed-method XHR ### 📊 Changes **2 files changed** (+112 additions, -22 deletions) <details> <summary>View changed files</summary> 📝 `src/domain/javascriptStaticAnalysisHelpers.ts` (+87 -21) 📝 `src/domain/webBundleAnalyzer.test.ts` (+25 -1) </details> ### 📄 Description ## Summary Follow-up to #872 and #874, both merged. It restores endpoints that their receiver-spelling heuristics could drop, as flagged in Codex review: 1. **Computed-method XHR** (#872 was merged at its first commit, before the review fix): ```js xhr.open(method, "/dynamic-method"); // endpoint on 4.1.0, none on main since #872 ``` With a computed method, the second literal is now kept as the URL unless it is provably not one: a Node `fs.open` flag (`r`, `r+`, `w+`, `ax`, …), a reserved browsing-context name (`_blank`/`_self`/`_parent`/`_top`), or a call on a receiver spelled as a browsing context or document (see 2). Bare relative URLs such as `xhr.open(method, "api/users")` are therefore kept. 2. **Literal methods on any receiver:** `parent.open("GET", "/api")` and `self.open("post", "/x")` may be local XHR bindings. A literal HTTP method is read as XHR whatever the receiver is called. The browsing-context and document exclusion (`window`/`self`/`globalThis`/`top`/`parent`/`opener`/`frames`/`document.open`) applies only when the method is computed. `window.open(url, "/preview")` is therefore not an endpoint, while `parent.open("GET", "/api")` is. 3. **URL literals on collection-spelled receivers** (#874): `isKeyedCollectionReceiver` checks spellings, not bindings. A `get`/`delete` literal that is a URL or path therefore stays an endpoint, as in `new Headers().get("/users")` with an imported `Headers`, `api.headers.get("https://…")`, and `api.searchParams.delete("../search")`. Only non-URL keys on such receivers are skipped, for example `response.headers.get("content-type")` and `new URLSearchParams(s).get("q")`. Unchanged: `fs.open(path, "r")` and `window.open(url, "_blank")` produce no endpoint. **Residual ambiguity:** without binding resolution, `popup.open(url, "preview")` (computed method, non-keyword target name, aliased receiver) has the same syntax as an aliased `xhr.open(method, "api/users")`. It is still reported, as it was on 4.1.0. No schema or catalog change. ## Verification - `src/domain/webBundleAnalyzer.test.ts` parity cases cover every example above. The open case expects `/dynamic-method`, `/parent-xhr`, `/self-xhr`, and `api/relative` and excludes `/preview`, `./frame`, `/replace`, `r`, `w+`, `_blank`, and `_TOP`. The keyed-collection case expects `/users`, `https://api.example.test/headers`, and `../search` and still excludes `q`/`content-type`/`page`/`map-key`. Both fail on `main`. - `npm run check:changed` (37 files, 749 tests) passes. `npm run test:focused` on the JavaScript/Electron/web-bundle boundary and acceptance tests (63 files) also passes. It excludes the two V8 Inspector runtime files, which fail identically on unmodified `main` on this host. No Hopper/Ghidra/IDA verification is needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-16 21:17:08 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2313
No description provided.