Skip to content

fix(intercept): IIFE wrapping for installInterceptor/getInterceptedRequests#100

Merged
jackwener merged 2 commits intojackwener:mainfrom
Astro-Han:worktree-fix-intercept-98
Mar 19, 2026
Merged

fix(intercept): IIFE wrapping for installInterceptor/getInterceptedRequests#100
jackwener merged 2 commits intojackwener:mainfrom
Astro-Han:worktree-fix-intercept-98

Conversation

@Astro-Han
Copy link
Contributor

@Astro-Han Astro-Han commented Mar 19, 2026

Summary

Fixes #98 — INTERCEPT strategy commands fail to capture data.

1. Interceptor pipeline fix (page.ts)

Root cause: installInterceptor() and getInterceptedRequests() were changed from this.evaluate() to direct sendCommand('exec') during the daemon migration. This bypassed wrapForEval(), so CDP received bare arrow functions that were defined but never invoked.

Fix: restore this.evaluate() for both methods, so wrapForEval() wraps the arrow function as an IIFE (code)().

2. Twitter adapter fixes (followers, following, search, notifications)

With the interceptor pipeline working, discovered three additional issues preventing data capture:

  • SPA navigation: page.goto() resets JS context, losing the installed interceptor. Changed to install interceptor first, then navigate via SPA (click for followers/following, pushState+popstate for search/notifications) to preserve JS context.
  • Data path: GraphQL response is { data: { user: ... } }, not { data: { data: { user: ... } } }. Removed the extra .data level.
  • Author resolution: Twitter moved screen_name from legacy to core. Updated to try core.screen_name first with legacy fallback.
  • Selector update: Twitter changed /followers to /verified_followers.

3. Security hardening

  • JSON.stringify for all user input interpolated into evaluate() JS strings
  • Navigation validation: throw on SPA navigation failure instead of silent empty return

Also removed erroneous .filter(r => r?.url?.includes('Followers')) in followers.ts — interceptor stores response body JSON (no url field), pattern filtering happens at capture time.

Test plan

  • npm run typecheck passes
  • npx vitest run src/ — 213 unit tests pass
  • twitter followers --user elonmusk --limit 5 — returns data
  • twitter following --user elonmusk --limit 5 — returns data
  • twitter search --query "opencli" --limit 5 — returns data with correct author
  • twitter search --query "it's a test" — single quote in query handled safely
  • twitter notifications --limit 5 — returns data

…r/getInterceptedRequests

Root cause: daemon migration changed these methods from this.evaluate()
to direct sendCommand('exec'), losing the wrapForEval() IIFE wrapping.
CDP received bare arrow functions that were never invoked.

Fixes jackwener#98
…TERCEPT commands

- followers/following: install interceptor on profile page, then click
  followers/following link (SPA navigation preserves JS context).
  Use JSON.stringify for targetUser to prevent injection. Throw on
  navigation failure. Update selector: /verified_followers.
- notifications: install interceptor on home, then pushState+popstate
  to /notifications. Validate navigation URL.
- search: fix author resolution (core.screen_name, not legacy).
- All: fix GraphQL data path (remove extra .data level), update author
  resolution to try core.screen_name before legacy.screen_name.
- followers: remove erroneous .filter(r => r?.url) — interceptor stores
  response body JSON, URL filtering happens at capture time.
@Astro-Han Astro-Han force-pushed the worktree-fix-intercept-98 branch from 8b11115 to f9d304d Compare March 19, 2026 15:39
@jackwener
Copy link
Owner

Thanks for the contribution. This was a very helpful fix. Restoring the interceptor path in page.ts addresses the actual regression from the daemon migration, and the follow-up Twitter adapter updates make the INTERCEPT commands usable again on the current X frontend. I especially appreciated the careful notes in the PR description and the extra hardening around SPA navigation and JSON.stringify for injected values.

@jackwener jackwener merged commit 65e30b9 into jackwener:main Mar 19, 2026
9 checks passed
@Astro-Han
Copy link
Contributor Author

Thank you! Glad the investigation into the IIFE wrapping root cause was useful. Debugging the SPA navigation was a fun puzzle — the pushState + popstate trick for search/notifications and the verified_followers selector change were unexpected discoveries along the way.

Note: the upstream search.ts uses the search-input approach for SPA navigation. I kept that as-is and only added the core.screen_name author fix on top — should be a clean merge with future changes to that file.

Happy to help with more adapters if needed!

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.

[Bug]: INTERCEPT strategy commands never capture data — generated JS not executed as IIFE

2 participants