tap.nav.push moves inside it,
useTapParams() reads the segments, and tap.nav.setSearch keeps a selection in the URL so
a link reopens what the owner was looking at.
What the segments look like
useTapParams() hands back the sub-path split for you, keyed by position. There are no named
parameters, because your page declares no route pattern for the host to match.
On
/projects/prj_1/ext/funnel-lab/explore/funnels/123 that is
{ pageId: "explore", path: "funnels/123", "0": "funnels", "1": "123" }.
Where you can go
A path that starts with
/projects/ is taken as written; anything else is resolved under
/projects/:projectId/ext/:extensionId, which is why the sample above begins with the page
id. A target outside the current project does not navigate: the owner gets a toast naming
your extension, and the page stays where it was.
Those five calls are the whole of navigation. The host owns the router, which is what keeps a
failing extension from taking the page with it.
Leaving Tappify
openExternal is the only way out, and the host draws the exit itself: a confirmation naming
your extension and the URL, then a new tab. The expand panel’s footer carries the same exit,
labelled with your extension’s name.
Two other escapes exist for the same reason — your code cannot reach the host’s DOM: