Skip to content

feat(deeplink): look up only links on the workspace's link hosts, and name the app on every request - #16

Merged
onamfc merged 2 commits into
mainfrom
feat/link-domains
Oct 21, 2026
Merged

onamfc merged 2 commits into
mainfrom
feat/link-domains

Conversation

@onamfc

@onamfc onamfc commented Oct 21, 2026

Copy link
Copy Markdown
Member

Summary

Pass every URI that opens the app to handleDeepLink; the SDK now decides which are LinkForty links.

  • App token header. With an appToken, every request carries X-LinkForty-App-Token, so a server that supports it answers with the app's own workspace's links only.
  • Link domains. With an appToken, initialize() fetches the workspace's link hosts from GET /api/sdk/v1/link-domains in the background (not blocking the install report) and stores them on the device (com.linkforty.sdk.linkDomains). A 200 replaces the list, a 400/404 clears it, any other failure keeps it. A stored list is used at once on later launches.
  • handleDeepLink(uri): Boolean. true when the URI is looked up as a LinkForty link:
    • a web (http/https) URI whose host (case-insensitive, port ignored) is the baseURL host or a known link domain → resolved on the server, as before;
    • any web URI while the domains are unknown (no app token, nothing fetched yet) → resolved, as before;
    • a web URI on another host once the domains are known, or any other scheme (myapp://…) → no request; onDeepLink receives the URI's own parameters (no linkId), the same data a failed lookup delivered.
  • Held links. A URI handed over before initialize() is held as before. On a launch with no stored domain list it waits up to 3 seconds for the domain fetch, then is decided against what is known; with a stored list (or no app token) it is decided at once. A held URI returns true for a web URI.

Behavior change

  • Custom-scheme URIs, and web URIs on hosts that aren't the workspace's link hosts, are no longer looked up. Every URI used to be sent to the resolve endpoint, so an app's own URL (https://acme.com/settings/abc) could match another link's short code and receive its data.
  • handleDeepLink's return type changed from Unit to Boolean. Kotlin and Java callers compile unchanged; a library compiled against 1.5.x that calls it must be recompiled.

Both are listed under Changed in the CHANGELOG.

Server

Uses the resolve endpoint's app-token scoping (X-LinkForty-App-Token, @linkforty/core with header scoping) and the link-domains endpoint on LinkForty Cloud. Against a server without them, the header is ignored and the domain fetch fails, so the domains stay unknown and every web URI is looked up, as before; custom-scheme URIs still make no request.

Tests

  • Unit: 195 passed (181 before). New LinkDomainsTest (14): the host rule (known domains, baseURL host, other hosts, unknown domains, custom schemes, case and port); the fetched list lower-cased and stored; a stored list used before any fetch; 404/400 clear it, a network error or 5xx keeps it; the header present only with an appToken; the handler resolves a link with one request and makes none for another web URI or a custom scheme, delivering the local parse.
  • Instrumented (API 34 emulator): 19 passed. New LinkDomainsFlowTest: after the domain fetch, https://acme.com/… and myapp://… return false with no resolve request and https://links.acme.com/abc123 returns true and resolves, every request carrying the token; a link held before initialize() with a slow (1 s) domain fetch is decided against the fetched list.
  • Without the change: looking up every URI and dropping the header fails 3 unit tests; deciding held links without waiting fails the held-link instrumented test.
  • Lint: no new findings.
  • E2E (e2e/run.mjs, emulator + Chrome, local server with the scoping and link-domains endpoints): 86 passed, 0 failed. New shared scenarios: a URL on another host is not looked up; a custom-scheme URL is not looked up; another workspace's link is not resolved for this app; a link opened while the app runs reports handled = true.

Decisions

  • No appToken: no domain fetch, held links are decided at once, and every web URI is looked up as before.
  • clearData() keeps the stored domain list: it describes the workspace, not the user.
  • A web URI with no host is not looked up.
  • The 3-second wait applies only on a launch with no stored list.

…app token

With an appToken, every request carries X-LinkForty-App-Token, and
initialize() fetches the workspace's link domains in the background
(GET /api/sdk/v1/link-domains), storing them on the device: a 200 replaces
the list, a 400 or 404 clears it, any other failure keeps it.

handleDeepLink(uri) returns whether it looks the URI up. A web URI on a
link domain or on the baseURL host is resolved on the server, as is any
web URI while the domains are unknown. A custom-scheme URI, and a web URI
on another host once the domains are known, make no request; onDeepLink
receives the URI's own parameters. A link held before initialize() waits
up to 3 seconds for the first domain fetch on a launch with no stored list.
…space's link is not resolved

Shared harness: a URL on a host that is not a link host and a custom-scheme
URL make no lookup and reach onDeepLink with their own parameters; another
workspace's link is not resolved for this app; a link opened while the app
runs reports handled = true.
@onamfc
onamfc merged commit ff974cc into main Oct 21, 2026
7 checks passed
@onamfc onamfc mentioned this pull request Oct 21, 2026
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