feat: add X (Twitter) deep link support#25
Conversation
WalkthroughX (Twitter) deep link support is introduced to the deep link handler system. A new xHandler is implemented to match and build deep links for X profile URLs, wired into the core handler registry, exported from the platforms module, the Platform type is expanded to include 'x', and a demo UI example link is added. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
apps/demo/index.html(1 hunks)package.json(1 hunks)packages/core/src/index.ts(2 hunks)packages/core/src/platforms/index.ts(1 hunks)packages/core/src/platforms/x.ts(1 hunks)packages/core/src/types.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/core/src/platforms/x.ts (1)
packages/core/src/types.ts (1)
DeepLinkHandler(10-13)
packages/core/src/index.ts (2)
packages/core/src/platforms/index.ts (4)
youtubeHandler(7-7)linkedinHandler(7-7)instagramHandler(7-7)xHandler(7-7)packages/core/src/platforms/instagram.ts (1)
instagramHandler(3-17)
🔇 Additional comments (6)
packages/core/src/types.ts (1)
1-1: LGTM!The Platform type is correctly extended to include the new 'x' literal, enabling type-safe recognition of X/Twitter as a supported platform.
packages/core/src/index.ts (2)
1-7: LGTM!The import statement is properly updated to include xHandler from the platforms module, maintaining alphabetical ordering within the destructured imports.
12-12: LGTM!The xHandler is correctly added to the handlers array, enabling X/Twitter URL matching in the generateDeepLink function. The handler placement at the end of the array is appropriate since handler order determines matching priority.
packages/core/src/platforms/index.ts (2)
5-5: LGTM!The xHandler import follows the established pattern for platform handlers.
7-7: LGTM!The xHandler is properly exported alongside existing handlers, making it available for external consumption via the public API.
packages/core/src/platforms/x.ts (1)
11-12: iOS deep link scheme should usetwitter://instead ofx://; Android package name is correct.The official X Developer documentation specifies the iOS URL scheme as
twitter://user?id=12345, notx://. The code currently usesx://user?screen_name=which deviates from documented schemes. Additionally, the documented format uses a numeric ID parameter rather thanscreen_name.The Android package name
com.twitter.androidremains correct and unchanged after rebranding, so that part of the implementation is confirmed.Recommend updating the iOS scheme to match official documentation or testing the current
x://scheme to confirm it works on recent X app versions, as there's no official documentation for thex://protocol.
| <a href="#" class="example-link x-link" data-url="https://x.com/"> | ||
| <span class="link-icon">🆇</span> | ||
| <span class="link-text">X Profile</span> | ||
| </a> |
There was a problem hiding this comment.
The demo URL is incomplete and won't match the handler regex.
The X Profile example link uses data-url="https://x.com/" which is missing a username. The xHandler regex in packages/core/src/platforms/x.ts (Line 4) expects a username: /https?:\/\/(?:www\.)?x\.com\/([^/?]+)/. This URL will fail to match and won't generate deep links when clicked in the demo.
🔎 Proposed fix: add a sample username
- <a href="#" class="example-link x-link" data-url="https://x.com/">
+ <a href="#" class="example-link x-link" data-url="https://x.com/elonmusk">
<span class="link-icon">🆇</span>
<span class="link-text">X Profile</span>
</a>📝 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.
| <a href="#" class="example-link x-link" data-url="https://x.com/"> | |
| <span class="link-icon">🆇</span> | |
| <span class="link-text">X Profile</span> | |
| </a> | |
| <a href="#" class="example-link x-link" data-url="https://x.com/elonmusk"> | |
| <span class="link-icon">🆇</span> | |
| <span class="link-text">X Profile</span> | |
| </a> |
🤖 Prompt for AI Agents
In apps/demo/index.html around lines 38 to 41, the X Profile example uses
data-url="https://x.com/" which lacks a username and therefore won't match the
xHandler regex; update the data-url to include a sample username (e.g.
data-url="https://x.com/sampleuser") so the regex
/https?:\/\/(?:www\.)?x\.com\/([^/?]+)/ will match and deep links are generated
when the demo link is clicked.
| "@typescript-eslint/eslint-plugin": "^8.50.0", | ||
| "@typescript-eslint/parser": "^8.50.0", | ||
| "eslint": "^9.39.2", | ||
| "eslint": "^8.57.1", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat package.json | head -50Repository: mdsaban/universal-app-opener
Length of output: 909
Justify the ESLint version downgrade to ^8.57.1.
The version range of ESLint currently supported by @typescript-eslint is ^8.57.0 || ^9.0.0. The downgrade from ^9.39.2 to ^8.57.1 is not required for compatibility with @typescript-eslint v8.50.0 and appears unrelated to adding X deep link support. If this change is intentional (e.g., due to configuration migration constraints or other reasons), please document the justification in the PR description.
🤖 Prompt for AI Agents
In package.json around line 15, the ESLint version was downgraded to "eslint":
"^8.57.1" without justification; either revert the package.json change back to
the previous version (e.g., ^9.39.2) to preserve compatibility, or keep the
downgrade but add a clear justification to the PR description explaining why
^8.57.1 is required (compatibility constraint, config migration, CI/tooling
reasons, etc.); update the package.json only if necessary to match the justified
version and ensure it remains compatible with @typescript-eslint's supported
range.
| import { DeepLinkHandler } from '../types'; | ||
|
|
||
| export const xHandler: DeepLinkHandler = { | ||
| match: (url) => url.match(/https?:\/\/(?:www\.)?x\.com\/([^/?]+)/), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's run the provided test script
node << 'EOF'
const regex = /https?:\/\/(?:www\.)?x\.com\/([^/?]+)/;
const testUrls = [
"https://x.com/elonmusk",
"https://www.x.com/elonmusk",
"http://x.com/elonmusk",
"https://x.com/elonmusk/",
"https://x.com/elonmusk?some=param",
"https://x.com/elonmusk/status/123456",
"https://x.com/i/flow/login",
"https://x.com/home",
"https://x.com/explore"
];
console.log("Testing X URL regex pattern:\n");
testUrls.forEach(url => {
const match = url.match(regex);
console.log(`URL: ${url}`);
console.log(`Match: ${match ? match[1] : 'NO MATCH'}\n`);
});
EOFRepository: mdsaban/universal-app-opener
Length of output: 522
🏁 Script executed:
# Then check the file structure and location
find . -name "*.ts" -type f | grep -i "platform.*x\|x.*platform" | head -20Repository: mdsaban/universal-app-opener
Length of output: 145
🏁 Script executed:
cat -n ./packages/core/src/platforms/x.tsRepository: mdsaban/universal-app-opener
Length of output: 618
Ensure the regex pattern restricts to X profile URLs only.
The current regex /https?:\/\/(?:www\.)?x\.com\/([^/?]+)/ is too permissive. It matches and extracts values from non-profile URLs like x.com/i/flow/login, x.com/home, and x.com/explore, returning "i", "home", and "explore" respectively as usernames. These invalid values are then passed to the deep link builder, likely causing failures.
Since X usernames are limited to 1–15 characters and contain only letters, numbers, and underscores, tighten the pattern to /https?:\/\/(?:www\.)?x\.com\/([a-zA-Z0-9_]+)(?:\/|$|\?)/ or add a negative lookahead to exclude known non-profile paths like /status/, /i/, /home, /explore, etc.
🤖 Prompt for AI Agents
In packages/core/src/platforms/x.ts around line 4, tighten the URL matcher so it
only captures valid X profile usernames: restrict the captured segment to 1–15
characters consisting of letters, digits and underscores, and require a trailing
slash, end-of-string or query delimiter (or alternatively add a negative
lookahead to exclude known non-profile segments like "i", "home", "explore",
"status", etc.); update the match implementation accordingly so non-profile
paths no longer produce a fake username.
|
@mdsaban This Twitter handler looks the most solid so far compared to the others. Also, the changes to index.html, package.json, and pnpm-lock.yaml don’t seem necessary for the handler reverting them would keep the PR more focused. |
Summary
This pull request introduces deep link support for the X (Twitter) platform within the Universal App Opener core package.
Changes Included
x.tshandler to generate deep links for X profiles.index.tsto register the X handler.types.tsto extend deep link result types for X.Deep Link Behavior
x://user?screen_name=<username>intent://user?screen_name=<username>#Intent;scheme=x;package=com.twitter.android;endMotivation
This enhancement expands platform compatibility and allows users to open X links directly in the mobile app, improving user experience and feature coverage.
Testing
Notes
No breaking changes. Safe to merge.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.