[PR #1670] [MERGED] feat(javascript): recognize tRPC procedures and GraphQL operations #4740

Closed
opened 2026-10-31 00:54:33 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1670
Author: @pompiliodonatoapp
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/11/2026
Merged by: @morluto

Base: main ← Head: feat/rpc-endpoint-recognition


📝 Commits (4)

  • ee07ffd feat(javascript): recognize tRPC procedures and GraphQL operations
  • a79e816 fix(javascript): preserve RPC binding identity and bundled calls
  • 3d1db2c Merge remote-tracking branch 'origin/main' into codex/pr1670-rpc-fixes
  • b7b3153 style(reference-source): fix CI formatting

📊 Changes

11 files changed (+823 additions, -9 deletions)

View changed files

📝 docs/javascript-artifact-reconstruction.md (+40 -0)
➕ src/domain/javascript/javascriptRpcEndpoints.test.ts (+329 -0)
➕ src/domain/javascript/javascriptRpcEndpoints.ts (+322 -0)
📝 src/domain/javascript/javascriptSemanticAnalysis.ts (+36 -0)
📝 src/domain/javascript/javascriptStaticAnalysis.ts (+7 -0)
📝 src/domain/javascript/javascriptStaticAnalysisCalls.ts (+7 -0)
📝 src/domain/javascript/javascriptStaticAnalysisState.ts (+2 -0)
📝 src/domain/referenceSourceRequireBindings.ts (+3 -4)
📝 src/domain/webBundleAnalyzer.test.ts (+53 -0)
📝 src/domain/webBundleAnalyzerInspection.ts (+23 -2)
📝 tests/boundary/filesystem/referenceSourceShadowedRequire.test.ts (+1 -3)

📄 Description

Summary

Static analysis records RPC client syntax as network endpoint candidates in
both analyze_javascript_application and analyze_web_bundle. Before this
change, tRPC and GraphQL clients contributed no endpoints, because the calls
are not string-literal fetch/XHR/WebSocket arguments. No existing issue is
linked; this is proposed as an enhancement.

Problem and expected behavior

In a minified tRPC client, e.invoice.list.useQuery({...}) and
n.empresa.byCnpj.query(...) name server procedures that a feature trace
needs, and so do GraphQL documents such as
query ListarNotas($competencia: String!) { ... }. Expected: these appear as
endpoint candidates with an explicit mechanism, without turning Apollo, RxJS,
store or browser APIs into false procedures.

Change and scope

src/domain/javascript/javascriptRpcEndpoints.ts is a per-source pre-order
scan, used by both analyzers.

  • trpc:procedure:<method> records the static member path of
    root.<path>.<method>(...).
    • Hooks and TanStack option factories are recognized directly.
    • query/mutate need a root bound to
      createTRPCClient/createTRPCProxyClient, or a tRPC source marker
      (TRPCClientError, trpc-accept, /trpc) together with a path of at
      least two segments.
    • subscribe needs the marker plus a tRPC observer argument (onData,
      onError, onStarted, onStopped, onComplete,
      onConnectionStateChange).
    • Never procedures: this roots, browser globals, and any path containing
      an endpoints segment (RTK Query).
    • Cache-key helpers (queryKey and similar) issue no request and are
      excluded.
  • trpc:link:<link> records the literal url of httpLink,
    httpBatchLink, httpBatchStreamLink and httpSubscriptionLink.
  • graphql:<type> records named operations:
    • from string and cooked template literals, when the header is a valid
      GraphQL header (($, a directive, or { followed by a field name);
    • from precompiled OperationDefinition objects;
    • a graphql-tag loc.source.body copy is skipped.

Method, callback and factory names were checked against the @trpc/client
11.19 sources (clientCallTypeMap, TRPCSubscriptionObserver, index.ts
exports) and the tRPC 11 React and TanStack documentation.

Documented, not included:

  • leading carrier segments (webpack module bindings, properties holding the
    proxy) remain in the recorded path;
  • useUtils() helpers and useQueries are not recognized;
  • links whose callee name was renamed by a minifier are not recognized.

Contract and boundary impact

  • Semantic owner and earliest changed stage: domain static analysis
    (endpoint findings).
  • CLI and MCP/tool-catalog contract: no schema change. mechanism is a
    free string and kind stays network. New endpoint entries can appear in
    existing outputs.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: new endpoint
    candidates can add application-graph nodes and reconstruction obligations
    for recognized procedures.
  • Process execution, authorization, cleanup, or containment impact: none
    (AST only; nothing is evaluated).
  • Generated metadata, package, or installation impact: none
    (npm run docs:check passes).

Evidence and regression coverage

  • Tests added or updated:

    • src/domain/javascript/javascriptRpcEndpoints.test.ts (10 tests):
      • hooks on renamed roots; TanStack factories; bound vanilla clients;
      • marker plus segment rules; subscription observers;
      • Apollo, RxJS, store, RTK Query and browser-global negatives;
      • GraphQL text and documents; prose and i18n negatives;
      • graphql-tag deduplication; an unchanged fetch endpoint.
    • src/domain/webBundleAnalyzer.test.ts: a captured-script case.
  • Base reproduction or other evidence: source-derived. On ac9677bd,
    endpoint recognition reads only string-literal fetch/WebSocket/XHR/
    .get-style arguments and loadURL, so none of these shapes can produce a
    finding. The base was not executed against these fixtures.

  • User-visible output (analyze_javascript_application on a minified
    fixture, via the built stdio server, with the same commit content on base
    ac9677bd):

    {"endpoint_kind":"network","value":"/api/trpc","mechanism":"trpc:link:httpBatchLink"}
    {"endpoint_kind":"network","value":"invoice.list","mechanism":"trpc:procedure:useQuery"}
    {"endpoint_kind":"network","value":"invoice.create","mechanism":"trpc:procedure:useMutation"}
    {"endpoint_kind":"network","value":"empresa.byCnpj","mechanism":"trpc:procedure:query"}
    {"endpoint_kind":"network","value":"ListarNotas","mechanism":"graphql:query"}
    {"endpoint_kind":"network","value":"EmitirNota","mechanism":"graphql:mutation"}
    {"endpoint_kind":"network","value":"/api/health","mechanism":"call:fetch"}
    

    navigator.permissions.query, this.client.query and
    e.queryManager.query in the same fixture were not reported.

  • Remaining proof gaps:

    • precision was not measured on a corpus of production bundles;
    • analyze_web_bundle was exercised through captured-script unit input, not
      a live browser.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable
    (mechanism names the rule).
  • Artifact identity, source provenance, and failed attempts remain
    preserved (locations and module keys as for other endpoints).
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain
    visible (documented limitations).

Validation performed

All runs below were on Windows 11 x64 with Node 22.22.3.

On this branch (base 31bfff6f):

  • npm run typecheck: passed.
  • npm run check:fast: passed.
  • npm run verify:test-discovery: discovered all 796 test files exactly once.
  • npm run docs:check: passed.
  • npx vitest run src/domain/javascript/ src/domain/webBundleAnalyzer.test.ts:
    42 files and 802 tests passed. This includes every existing JavaScript
    static-analysis test, so no existing endpoint expectation changed.
  • The end-to-end fixture analysis could not be repeated on this base from a
    Windows source checkout. analyze_javascript_application now reports
    capability_unavailable because the Windows native controls manifest
    (native/windows/build/manifest.json) is not built in a source checkout.
    This is unrelated to this change.

On the previous base ac9677bd, with the same commit content:

  • The end-to-end analysis above passed.
  • npm run test:fast showed no failures beyond those also present on the
    base (see morluto/rea#1669).
  • npm run verify:architecture-guards: passed.
  • An independent review of an earlier revision of this scan, with the same
    linear, bounded structure, probed a 23 MB, 600k-node synthetic bundle. The
    added work took about 1 s, against about 200 s for the full analysis. This
    was not re-measured on the final revision.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Consumers asserting exact
    endpoint arrays may see new entries for tRPC/GraphQL sources.
  • Real Hopper/Ghidra, browser, or OS coverage: Windows 11 only; no live
    browser lane.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: syntax only.
    Recorded values are procedure names, operation names and literal link URLs,
    sanitized like other endpoint candidates.

🤖 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/1670 **Author:** [@pompiliodonatoapp](https://github.com/pompiliodonatoapp) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/11/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/rpc-endpoint-recognition` --- ### 📝 Commits (4) - [`ee07ffd`](https://github.com/morluto/rea/commit/ee07ffdf41c1bdca689db926f2328cfa6f2621b3) feat(javascript): recognize tRPC procedures and GraphQL operations - [`a79e816`](https://github.com/morluto/rea/commit/a79e816108bb25b1d96421faf807d9c03e4fdf83) fix(javascript): preserve RPC binding identity and bundled calls - [`3d1db2c`](https://github.com/morluto/rea/commit/3d1db2c4259bb0d98b35c4258658326e482b3f72) Merge remote-tracking branch 'origin/main' into codex/pr1670-rpc-fixes - [`b7b3153`](https://github.com/morluto/rea/commit/b7b3153734be2881858e8f0168e2b3ac856dcfcd) style(reference-source): fix CI formatting ### 📊 Changes **11 files changed** (+823 additions, -9 deletions) <details> <summary>View changed files</summary> 📝 `docs/javascript-artifact-reconstruction.md` (+40 -0) ➕ `src/domain/javascript/javascriptRpcEndpoints.test.ts` (+329 -0) ➕ `src/domain/javascript/javascriptRpcEndpoints.ts` (+322 -0) 📝 `src/domain/javascript/javascriptSemanticAnalysis.ts` (+36 -0) 📝 `src/domain/javascript/javascriptStaticAnalysis.ts` (+7 -0) 📝 `src/domain/javascript/javascriptStaticAnalysisCalls.ts` (+7 -0) 📝 `src/domain/javascript/javascriptStaticAnalysisState.ts` (+2 -0) 📝 `src/domain/referenceSourceRequireBindings.ts` (+3 -4) 📝 `src/domain/webBundleAnalyzer.test.ts` (+53 -0) 📝 `src/domain/webBundleAnalyzerInspection.ts` (+23 -2) 📝 `tests/boundary/filesystem/referenceSourceShadowedRequire.test.ts` (+1 -3) </details> ### 📄 Description ## Summary Static analysis records RPC client syntax as network endpoint candidates in both `analyze_javascript_application` and `analyze_web_bundle`. Before this change, tRPC and GraphQL clients contributed no endpoints, because the calls are not string-literal `fetch`/XHR/WebSocket arguments. No existing issue is linked; this is proposed as an enhancement. ## Problem and expected behavior In a minified tRPC client, `e.invoice.list.useQuery({...})` and `n.empresa.byCnpj.query(...)` name server procedures that a feature trace needs, and so do GraphQL documents such as `query ListarNotas($competencia: String!) { ... }`. Expected: these appear as endpoint candidates with an explicit `mechanism`, without turning Apollo, RxJS, store or browser APIs into false procedures. ## Change and scope `src/domain/javascript/javascriptRpcEndpoints.ts` is a per-source pre-order scan, used by both analyzers. - **`trpc:procedure:<method>`** records the static member path of `root.<path>.<method>(...)`. - Hooks and TanStack option factories are recognized directly. - `query`/`mutate` need a root bound to `createTRPCClient`/`createTRPCProxyClient`, or a tRPC source marker (`TRPCClientError`, `trpc-accept`, `/trpc`) together with a path of at least two segments. - `subscribe` needs the marker plus a tRPC observer argument (`onData`, `onError`, `onStarted`, `onStopped`, `onComplete`, `onConnectionStateChange`). - Never procedures: `this` roots, browser globals, and any path containing an `endpoints` segment (RTK Query). - Cache-key helpers (`queryKey` and similar) issue no request and are excluded. - **`trpc:link:<link>`** records the literal `url` of `httpLink`, `httpBatchLink`, `httpBatchStreamLink` and `httpSubscriptionLink`. - **`graphql:<type>`** records named operations: - from string and cooked template literals, when the header is a valid GraphQL header (`($`, a directive, or `{` followed by a field name); - from precompiled `OperationDefinition` objects; - a graphql-tag `loc.source.body` copy is skipped. Method, callback and factory names were checked against the `@trpc/client` 11.19 sources (`clientCallTypeMap`, `TRPCSubscriptionObserver`, `index.ts` exports) and the tRPC 11 React and TanStack documentation. Documented, not included: - leading carrier segments (webpack module bindings, properties holding the proxy) remain in the recorded path; - `useUtils()` helpers and `useQueries` are not recognized; - links whose callee name was renamed by a minifier are not recognized. ## Contract and boundary impact - **Semantic owner and earliest changed stage:** domain static analysis (endpoint findings). - **CLI and MCP/tool-catalog contract:** no schema change. `mechanism` is a free string and `kind` stays `network`. New endpoint entries can appear in existing outputs. - **Provider, bridge, target-format, or platform compatibility:** none. - **Evidence, artifact, provenance, or reconstruction contract:** new endpoint candidates can add application-graph nodes and reconstruction obligations for recognized procedures. - **Process execution, authorization, cleanup, or containment impact:** none (AST only; nothing is evaluated). - **Generated metadata, package, or installation impact:** none (`npm run docs:check` passes). ## Evidence and regression coverage - **Tests added or updated:** - `src/domain/javascript/javascriptRpcEndpoints.test.ts` (10 tests): - hooks on renamed roots; TanStack factories; bound vanilla clients; - marker plus segment rules; subscription observers; - Apollo, RxJS, store, RTK Query and browser-global negatives; - GraphQL text and documents; prose and i18n negatives; - graphql-tag deduplication; an unchanged `fetch` endpoint. - `src/domain/webBundleAnalyzer.test.ts`: a captured-script case. - **Base reproduction or other evidence:** source-derived. On `ac9677bd`, endpoint recognition reads only string-literal `fetch`/WebSocket/XHR/ `.get`-style arguments and `loadURL`, so none of these shapes can produce a finding. The base was not executed against these fixtures. - **User-visible output** (`analyze_javascript_application` on a minified fixture, via the built stdio server, with the same commit content on base `ac9677bd`): ```text {"endpoint_kind":"network","value":"/api/trpc","mechanism":"trpc:link:httpBatchLink"} {"endpoint_kind":"network","value":"invoice.list","mechanism":"trpc:procedure:useQuery"} {"endpoint_kind":"network","value":"invoice.create","mechanism":"trpc:procedure:useMutation"} {"endpoint_kind":"network","value":"empresa.byCnpj","mechanism":"trpc:procedure:query"} {"endpoint_kind":"network","value":"ListarNotas","mechanism":"graphql:query"} {"endpoint_kind":"network","value":"EmitirNota","mechanism":"graphql:mutation"} {"endpoint_kind":"network","value":"/api/health","mechanism":"call:fetch"} ``` `navigator.permissions.query`, `this.client.query` and `e.queryManager.query` in the same fixture were not reported. - **Remaining proof gaps:** - precision was not measured on a corpus of production bundles; - `analyze_web_bundle` was exercised through captured-script unit input, not a live browser. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable (`mechanism` names the rule). - [x] Artifact identity, source provenance, and failed attempts remain preserved (locations and module keys as for other endpoints). - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible (documented limitations). ## Validation performed All runs below were on Windows 11 x64 with Node 22.22.3. On this branch (base `31bfff6f`): - `npm run typecheck`: passed. - `npm run check:fast`: passed. - `npm run verify:test-discovery`: discovered all 796 test files exactly once. - `npm run docs:check`: passed. - `npx vitest run src/domain/javascript/ src/domain/webBundleAnalyzer.test.ts`: 42 files and 802 tests passed. This includes every existing JavaScript static-analysis test, so no existing endpoint expectation changed. - The end-to-end fixture analysis could not be repeated on this base from a Windows source checkout. `analyze_javascript_application` now reports `capability_unavailable` because the Windows native controls manifest (`native/windows/build/manifest.json`) is not built in a source checkout. This is unrelated to this change. On the previous base `ac9677bd`, with the same commit content: - The end-to-end analysis above passed. - `npm run test:fast` showed no failures beyond those also present on the base (see morluto/rea#1669). - `npm run verify:architecture-guards`: passed. - An independent review of an earlier revision of this scan, with the same linear, bounded structure, probed a 23 MB, 600k-node synthetic bundle. The added work took about 1 s, against about 200 s for the full analysis. This was not re-measured on the final revision. ## Compatibility, safety, and release - **Breaking changes or migration steps:** none. Consumers asserting exact endpoint arrays may see new entries for tRPC/GraphQL sources. - **Real Hopper/Ghidra, browser, or OS coverage:** Windows 11 only; no live browser lane. - **Package or release metadata impact:** none. - **Security, privacy, process, or containment review:** syntax only. Recorded values are procedure names, operation names and literal link URLs, sanitized like other endpoint candidates. 🤖 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-31 00:54:33 +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#4740
No description provided.