Skip to content

fix: update ondemand.s regex for new webpack chunk format#411

Open
ryanstoic wants to merge 1 commit intod60:mainfrom
ryanstoic:fix/ondemand-regex-webpack-format
Open

fix: update ondemand.s regex for new webpack chunk format#411
ryanstoic wants to merge 1 commit intod60:mainfrom
ryanstoic:fix/ondemand-regex-webpack-format

Conversation

@ryanstoic
Copy link
Copy Markdown

@ryanstoic ryanstoic commented Mar 27, 2026

Problem

X changed how the ondemand.s JS bundle is referenced in their HTML (around March 18, 2026). The old webpack format embedded the hash directly next to the chunk name:

'ondemand.s': 'abc123'

The new format uses a numeric chunk index that maps to the hash in a separate JavaScript object:

,1234:"ondemand.s"  ...  ,1234:"abc123"

This causes ON_DEMAND_FILE_REGEX to fail, which means get_indices can't find the KEY_BYTE indices, raising Couldn't get KEY_BYTE indices for every API call.

Fix

Three changes in transaction.py:

  1. ON_DEMAND_FILE_REGEX — now captures the numeric chunk index instead of the hash directly
  2. ON_DEMAND_HASH_PATTERN (new) — uses the chunk index to find the actual hash in a second pass
  3. INDICES_REGEX — updated to match the new JS format ([N], 16 instead of (a[N], 16))
  4. get_indices — two-step lookup: find chunk index → resolve to file hash → fetch JS → extract indices

Testing

Tested and confirmed working as of 2026-03-26 in a tweet scheduling app that uses set_cookies + create_tweet + upload_media.

Fixes #408
Fixes #409

Summary by Sourcery

Update X client transaction logic to handle the new webpack chunk format for the ondemand.s bundle so KEY_BYTE indices can be resolved again.

Bug Fixes:

  • Adjust ondemand.s bundle detection to use the numeric chunk index and resolve the corresponding file hash from the updated HTML/JS format.
  • Update KEY_BYTE indices extraction to match the new JavaScript pattern emitted by the ondemand.s chunk.

Summary by CodeRabbit

  • Refactor
    • Improved internal transaction parsing logic with simplified and more efficient pattern matching for on-demand asset resolution, ensuring more reliable extraction of required indices during the transaction processing workflow.

X changed how the ondemand.s JS bundle is referenced in their HTML.
The old format embedded the hash directly next to the chunk name:
  'ondemand.s': 'abc123'

The new format uses a numeric chunk index that maps to the hash in
a separate JavaScript object:
  ,1234:"ondemand.s"  ...  ,1234:"abc123"

This updates ON_DEMAND_FILE_REGEX to capture the chunk index, adds
ON_DEMAND_HASH_PATTERN for the second lookup, and updates INDICES_REGEX
to match the new format. The get_indices method now does a two-step
lookup: find the chunk index, then resolve it to the file hash.

Fixes d60#408
Fixes d60#409
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 27, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Updates the client transaction logic to handle X/Twitter’s new webpack chunk format for the ondemand.s bundle by matching the numeric chunk index, resolving it to the hash, and adapting the index extraction regex accordingly.

Sequence diagram for updated get_indices ondemand.s resolution

sequenceDiagram
    actor User
    participant App
    participant ClientTransaction
    participant XHomePage as X_home_page
    participant AbsTwimg as abs_twid_img

    User->>App: Trigger API call (e.g. create_tweet)
    App->>ClientTransaction: get_indices(home_page_response, session, headers)

    ClientTransaction->>ClientTransaction: validate_response(home_page_response)
    ClientTransaction->>ClientTransaction: ON_DEMAND_FILE_REGEX.search(response)
    alt ondemand.s chunk index found
        ClientTransaction->>ClientTransaction: Extract chunk_index (group 1)
        ClientTransaction->>ClientTransaction: re.search(ON_DEMAND_HASH_PATTERN.format(chunk_index), response)
        alt hash found
            ClientTransaction->>ClientTransaction: Extract file_hash (group 1)
            ClientTransaction->>AbsTwimg: GET https://abs.twimg.com/.../ondemand.s.{file_hash}a.js
            AbsTwimg-->>ClientTransaction: ondemand.s JS bundle
            ClientTransaction->>ClientTransaction: INDICES_REGEX.finditer(js_text)
            ClientTransaction->>ClientTransaction: Collect key_byte_indices (group 1)
        else hash not found
            ClientTransaction->>ClientTransaction: key_byte_indices remains empty
        end
    else ondemand.s chunk index not found
        ClientTransaction->>ClientTransaction: key_byte_indices remains empty
    end

    ClientTransaction->>ClientTransaction: if not key_byte_indices: raise Exception
    ClientTransaction-->>App: key_byte_indices (list[int])
    App-->>User: Continue request flow using KEY_BYTE indices
Loading

File-Level Changes

Change Details Files
Adjust ondemand.s bundle discovery to work with the new webpack chunk format that uses numeric chunk indices.
  • Update ON_DEMAND_FILE_REGEX to capture the numeric chunk index associated with "ondemand.s" instead of the hash value
  • Introduce ON_DEMAND_HASH_PATTERN to look up the ondemand.s hash using the captured chunk index in the same HTML/JS response
  • Change get_indices to first extract the ondemand.s chunk index, then resolve it to a hash, build the ondemand.s URL, and fetch the JS bundle accordingly
twikit/x_client_transaction/transaction.py
Update KEY_BYTE indices extraction to match the new JavaScript call-site format.
  • Simplify INDICES_REGEX to match the new "[N], 16" pattern instead of the older "(a[N], 16)" structure
  • Adjust get_indices to collect indices from INDICES_REGEX using the correct capturing group and convert them to integers before returning
twikit/x_client_transaction/transaction.py

Assessment against linked issues

Issue Objective Addressed Explanation
#408 Update ClientTransaction ondemand.s-related parsing (regex and index extraction) so that KEY_BYTE indices can be found with the new ondemand.s bundle/webpack format, avoiding the Couldn't get KEY_BYTE indices exception.
#408 Restore normal ClientTransaction behavior so that API calls no longer fail (including avoiding the 'ClientTransaction' object has no attribute 'key' error caused by missing KEY_BYTE indices).
#409 Fix the client transaction logic so that get_indices can successfully retrieve KEY_BYTE indices instead of raising "Couldn't get KEY_BYTE indices".

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Updated regex patterns and parsing logic in ClientTransaction.get_indices() to accommodate Twitter's changed ondemand.s.js structure. The method now extracts the on-demand chunk index and asset hash using new regex definitions, then builds URLs from the extracted hash instead of the chunk identifier.

Changes

Cohort / File(s) Summary
Transaction Parsing Logic
twikit/x_client_transaction/transaction.py
Refactored ondemand chunk detection with simplified regex pattern; added ON_DEMAND_HASH_PATTERN for asset hash extraction; adjusted capture group indices in INDICES_REGEX from group(2) to group(1); regenerated global regex definitions to align with Twitter's updated JavaScript structure.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A regex fix hops into play,
Twitter changed their way,
ondemand.s dances anew,
KEY_BYTE patterns shine through,
APIs dance again, hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: updating the ondemand.s regex to handle a new webpack chunk format, which matches the primary objective of fixing the parsing logic.
Linked Issues check ✅ Passed The pull request directly addresses the linked issues by updating regex patterns and implementing two-step lookup logic to resolve the new ondemand.s.js webpack format, restoring ClientTransaction functionality.
Out of Scope Changes check ✅ Passed All changes in transaction.py are directly scoped to the ondemand.s regex and KEY_BYTE indices extraction logic, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new ON_DEMAND_HASH_PATTERN only matches double-quoted hashes (,{}:"([0-9a-f]+)"), whereas ON_DEMAND_FILE_REGEX allows both single and double quotes; consider making the hash pattern consistent so it continues to work if the HTML switches to single quotes for hashes.
  • Since you're now using a two-step lookup by chunk index, it may be safer to tighten both regexes with clearer boundaries (e.g., ensuring the preceding character is not a digit and the following character is not part of a longer identifier) to avoid accidentally matching unrelated ,1234: or ,[N], 16 sequences in other parts of the page.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `ON_DEMAND_HASH_PATTERN` only matches double-quoted hashes (`,{}:"([0-9a-f]+)"`), whereas `ON_DEMAND_FILE_REGEX` allows both single and double quotes; consider making the hash pattern consistent so it continues to work if the HTML switches to single quotes for hashes.
- Since you're now using a two-step lookup by chunk index, it may be safer to tighten both regexes with clearer boundaries (e.g., ensuring the preceding character is not a digit and the following character is not part of a longer identifier) to avoid accidentally matching unrelated `,1234:` or `,[N], 16` sequences in other parts of the page.

## Individual Comments

### Comment 1
<location path="twikit/x_client_transaction/transaction.py" line_range="17-21" />
<code_context>
-INDICES_REGEX = re.compile(
-    r"""(\(\w{1}\[(\d{1,2})\],\s*16\))+""", flags=(re.VERBOSE | re.MULTILINE))
+    r',(\d+):["\']ondemand\.s["\']', flags=(re.VERBOSE | re.MULTILINE))
+ON_DEMAND_HASH_PATTERN = r',{}:"([0-9a-f]+)"'
+INDICES_REGEX = re.compile(r'\[(\d+)\],\s*16')

</code_context>
<issue_to_address>
**issue:** Hash pattern only matches double-quoted hashes while the ondemand.s key allows both quote styles.

Because `ON_DEMAND_HASH_PATTERN` only matches double-quoted hashes, `re.search` will fail whenever the hash is single-quoted (e.g. `,123:'abcd'`), so `on_demand_file_url` is never constructed and you hit `Couldn't get KEY_BYTE indices`. To avoid this, update the hash pattern to accept both quote styles, e.g. `r',{}:["\']([0-9a-f]+)["\']'` so it stays consistent with `ON_DEMAND_FILE_REGEX`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +17 to 21
ON_DEMAND_HASH_PATTERN = r',{}:"([0-9a-f]+)"'
INDICES_REGEX = re.compile(r'\[(\d+)\],\s*16')


class ClientTransaction:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Hash pattern only matches double-quoted hashes while the ondemand.s key allows both quote styles.

Because ON_DEMAND_HASH_PATTERN only matches double-quoted hashes, re.search will fail whenever the hash is single-quoted (e.g. ,123:'abcd'), so on_demand_file_url is never constructed and you hit Couldn't get KEY_BYTE indices. To avoid this, update the hash pattern to accept both quote styles, e.g. r',{}:["\']([0-9a-f]+)["\']' so it stays consistent with ON_DEMAND_FILE_REGEX.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@twikit/x_client_transaction/transaction.py`:
- Around line 15-18: The ON_DEMAND_HASH_PATTERN currently only matches
double-quoted hashes which can miss single-quoted webpack outputs; update
ON_DEMAND_HASH_PATTERN to accept either single or double quotes around the hash
(similar to ON_DEMAND_FILE_REGEX) so both quote styles are handled
consistently—modify the pattern referenced as ON_DEMAND_HASH_PATTERN to use a
quote-capturing alternative like ["'] around the hash value and ensure any
backreference logic matches that capture.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ec057d6-1634-405a-b9e7-e7769470e479

📥 Commits

Reviewing files that changed from the base of the PR and between c3b7220 and 4a62e28.

📒 Files selected for processing (1)
  • twikit/x_client_transaction/transaction.py

Comment on lines 15 to +18
ON_DEMAND_FILE_REGEX = re.compile(
r"""['|\"]{1}ondemand\.s['|\"]{1}:\s*['|\"]{1}([\w]*)['|\"]{1}""", flags=(re.VERBOSE | re.MULTILINE))
INDICES_REGEX = re.compile(
r"""(\(\w{1}\[(\d{1,2})\],\s*16\))+""", flags=(re.VERBOSE | re.MULTILINE))
r',(\d+):["\']ondemand\.s["\']', flags=(re.VERBOSE | re.MULTILINE))
ON_DEMAND_HASH_PATTERN = r',{}:"([0-9a-f]+)"'
INDICES_REGEX = re.compile(r'\[(\d+)\],\s*16')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Quote character inconsistency between regex patterns.

ON_DEMAND_FILE_REGEX correctly handles both single and double quotes around ondemand.s, but ON_DEMAND_HASH_PATTERN only matches double quotes around the hash value. If the webpack output uses single quotes for hashes (as it might for chunk names), the second lookup will fail silently.

Proposed fix to handle both quote types
-ON_DEMAND_HASH_PATTERN = r',{}:"([0-9a-f]+)"'
+ON_DEMAND_HASH_PATTERN = r',{}:["\']([0-9a-f]+)["\']'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ON_DEMAND_FILE_REGEX = re.compile(
r"""['|\"]{1}ondemand\.s['|\"]{1}:\s*['|\"]{1}([\w]*)['|\"]{1}""", flags=(re.VERBOSE | re.MULTILINE))
INDICES_REGEX = re.compile(
r"""(\(\w{1}\[(\d{1,2})\],\s*16\))+""", flags=(re.VERBOSE | re.MULTILINE))
r',(\d+):["\']ondemand\.s["\']', flags=(re.VERBOSE | re.MULTILINE))
ON_DEMAND_HASH_PATTERN = r',{}:"([0-9a-f]+)"'
INDICES_REGEX = re.compile(r'\[(\d+)\],\s*16')
ON_DEMAND_FILE_REGEX = re.compile(
r',(\d+):["\']ondemand\.s["\']', flags=(re.VERBOSE | re.MULTILINE))
ON_DEMAND_HASH_PATTERN = r',{}:["\']([0-9a-f]+)["\']'
INDICES_REGEX = re.compile(r'\[(\d+)\],\s*16')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@twikit/x_client_transaction/transaction.py` around lines 15 - 18, The
ON_DEMAND_HASH_PATTERN currently only matches double-quoted hashes which can
miss single-quoted webpack outputs; update ON_DEMAND_HASH_PATTERN to accept
either single or double quotes around the hash (similar to ON_DEMAND_FILE_REGEX)
so both quote styles are handled consistently—modify the pattern referenced as
ON_DEMAND_HASH_PATTERN to use a quote-capturing alternative like ["'] around the
hash value and ensure any backreference logic matches that capture.

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.

Couldn't get KEY_BYTE indices Title: ClientTransaction broken as of March 18 2026 — Couldn't get KEY_BYTE indices

1 participant