- Migrate user profile fields from `legacy{}` to `core{}` / `avatar{}` / `location{}` (with legacy fallback for older response shapes). Affects `user`, `whoami`, `status`, `followers`, `following`.
- Fix `user-posts` empty results: add missing `includePromotedContent` variable and update `instructions` path from `timeline_v2` to `timeline`.
- Switch `followers` / `following` to POST (Twitter changed the requirement).
- Refresh 16 stale `FALLBACK_QUERY_IDS` from fa0311/twitter-openapi.
- Drop `legacy{}` early-return in `parse_user_result`; key existence on `rest_id` so followers/following keep working when Twitter fully drops legacy.
- Add unit tests for the new core/avatar/location fallback chain and rest_id/typename guards.
Twitter migrated SearchTimeline from GET to POST; update fetch_search
to route through _graphql_post via a new use_post flag on _fetch_timeline,
avoiding duplicating the pagination logic (closes#39, refs #40, #42).
Also guard against get_ondemand_file_url returning None so the error
message is clear instead of crashing on NoneType.split (closes #43-adjacent).
Refresh all FALLBACK_QUERY_IDS from live JS bundles — 18 operations updated.
Add `twitter bookmarks folders` command to list bookmark folders
and `twitter bookmarks folders <id>` to fetch tweets from a specific
folder, with --since date filtering and pagination support.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Twitter now returns HTTP 422 GRAPHQL_VALIDATION_FAILED (not just 404)
when a queryId goes stale. Updated fallback IDs and added 422 to the
stale-queryId retry logic in both _graphql_get and _graphql_post.
Split the monolithic client.py (1341 lines) into three focused modules:
- graphql.py (~200 lines): queryId resolution, URL building, JS bundle
scanning, feature flag management
- parser.py (~270 lines): Tweet/User/Media/Article parsing, utility functions
(_deep_get, _parse_int, _extract_cursor, _extract_media)
- client.py (~700 lines): TwitterClient class with HTTP engine, anti-detection,
session management, and all public API methods
Backward compatibility: client.py re-exports all previously public symbols
so existing test imports work without modification. 88/88 tests pass.