Skip to content

fix(android): hand no_applink URLs to InAppBrowser - #225

Merged
yodem merged 1 commit into
masterfrom
fix/aasa-android-no-applink
Sep 24, 2026
Merged

yodem merged 1 commit into
masterfrom
fix/aasa-android-no-applink

Conversation

@yodem

@yodem yodem commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Android App Links claim sefaria.org / .il wholesale (autoVerify, no pathPattern), so the post-login landing is captured even though the manifest cannot exclude by query.
  • Generalise the existing set-language-cookie bailout in DeepLinkRouter.route() into a BROWSER_ONLY_QUERY_KEYS list that also includes no_applink.
  • Match on key presence (k in query), not === '1', so ?no_applink, ?no_applink=, and ?no_applink=1 all hand off to catchAll → openUri (InAppBrowser / Custom Tabs). Check runs before the decodeURIComponent reduce.

Pairs with Sefaria-Project nginx unshadow (AASA currently hardcoded at the edge) and PR #3631 (no_applink query marker). This change is inert until #3631 deploys a no_applink param; set-language-cookie behaviour is unchanged.

Test plan

  • npx jest __tests__/DeepLinkRouter.test.js --watchAll=false — 21/21 passing
  • Device: post-login landing with no_applink=1 opens InAppBrowser / Custom Tabs, not an in-app text ref
  • Device: ?set-language-cookie= language switch still leaves the app the same way as before
  • Device: ordinary /Genesis.1.1 and /texts deep links still open in-app

Made with Cursor

Android App Links claim sefaria.org wholesale, so the post-login landing
is captured even though the manifest cannot exclude by query. Generalise
the set-language-cookie bailout to a list of browser-only query keys.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gitvelocity-reviewer

Copy link
Copy Markdown

📊 Code Quality Score: 5/100

Base Score 20 × Effort Scale Factor 0.25 = 5

Category Score Factors
🔭 Scope 5/20 DeepLinkRouter.js and __tests__/DeepLinkRouter.test.js are the two files touched. The change is confined to a single guard block inside the route method; no new public API, no new component, no cross-subsystem wiring.
🏗️ Architecture 2/20 The single-key if ('set-language-cookie' in query) check is replaced by an array lookup via BROWSER_ONLY_QUERY_KEYS.some(). No module boundary changed, no new dependency introduced.
⚙️ Implementation 4/20 BROWSER_ONLY_QUERY_KEYS is declared as a local const array inside the method body and iterated with Array.prototype.some. The in operator preserves the key-presence-only semantics of the original check, handling valueless, empty-value, and valued query params uniformly.
⚠️ Risk 4/20 A wrong value in BROWSER_ONLY_QUERY_KEYS would silently redirect a valid deep link to the browser instead of opening it in-app, which is user-visible but reversible by removing the key. The original set-language-cookie path is structurally unchanged; a regression there would be caught by the existing describe('DeepLinkRouter interface language switching') suite.
✅ Quality 4/15 __tests__/DeepLinkRouter.test.js adds one describe block with test.each covering four no_applink URL variants (value, empty, valueless, .il domain) and one negative case asserting openUri is not called on an ordinary URL. No test re-exercises set-language-cookie through the refactored code path directly, though the pre-existing suite covers it.
🔒 Perf / Security 1/5 No performance or security work is present beyond the existing pattern of handing browser-only URLs to openUri rather than the in-app navigator.

Was this score accurate? 👍 Yes · 👎 No

How this was scored →

Scored by GitVelocity · How are scores calculated?

@yodem
yodem requested a review from YishaiGlasner September 15, 2026 08:04
@yodem
yodem merged commit e7f76e5 into master Sep 24, 2026
@gitvelocity-reviewer

Copy link
Copy Markdown

📊 Code Quality Score: 7/100

28 × 0.25 (Micro ESF) = 7

Category Score Factors
🔭 Scope 4/20 Two files are modified: DeepLinkRouter.js (production routing logic) and tests/DeepLinkRouter.test.js (test coverage). The change is contained within the deep link routing subsystem and does not touch any other module or service.
🏗️ Architecture 3/20 The single string comparison is replaced by a named constant array BROWSER_ONLY_QUERY_KEYS checked with Array.some(). No new module boundary is introduced and no dependency changes.
⚙️ Implementation 5/20 The production change replaces one 'in' check with BROWSER_ONLY_QUERY_KEYS.some((key) => key in query). The test block uses test.each over four URL variants to drive router.route() and assert openUri is called while openRef is not.
⚠️ Risk 5/20 The change sits on the deep link routing path, which determines whether a URL opens inside the app or hands off to the browser. The existing set-language-cookie behavior is preserved unchanged; no_applink is additive. A wrong entry in BROWSER_ONLY_QUERY_KEYS would strand users in the wrong context, but the change is easily reverted.
✅ Quality 10/15 The new describe block in DeepLinkRouter.test.js uses test.each to cover no_applink with a value, with an empty value, with no value, and on the .il domain, plus one negative test confirming ordinary deep links still open in-app. No E2E test accompanies the change.
🔒 Perf / Security 1/5 No benchmarks or explicit security analysis. The change is defensive in that it prevents the app from intercepting post-login browser sessions that carry no_applink.

Was this score accurate? 👍 Yes · 👎 No

How this was scored →

Scored by GitVelocity · How are scores calculated?

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.

2 participants