fix(navigation): ignore unknown query parameters on Buzz links and remove the buzz://open locator - #457
Conversation
Buzz links now drop any query parameter outside their grammar, values and repeats included, instead of failing as invalid-target: `message` keeps only channel, id and thread, the `channel` forms ignore the whole query, and the entity hosts keep only their per-type keys, so `commit` on a project and `tab` on a PR or issue are ignored too. A duplicated known key such as channel=a&channel=b is still ambiguous and rejects. This matches the original Buzz desktop client's lax message-link handling while staying strict on duplicated known keys. Credentials, port, fragment, the length cap, the lowercase scheme requirement and the OS-boundary refusal of buzz://open are unchanged. Everything rebuilt from a parsed link (entityHref, Copy link, the browser address) already emits the canonical form without the extra parameters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
…r strictness Follow-up to ed16fc2 with no behaviour change. The routes test now covers `buzz://project?owner=…&d=…&tab=commits&commit=<hash>`, the one lax shape where the ignored value looks meaningful: it parses to the project's commits section with no commit hash, and `entityHref` of the result is the canonical project link with `tab=commits` only. docs/deep-links.md now says the unknown-parameter rule does not extend to `buzz://open?target=…` locators, which still require exactly one `target` key, so readers do not assume every Buzz link became permissive. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
`buzz://open?target=<json>` is no longer a Buzz link anywhere in buzz-app. `parseBuzzLink` returns null for it, so in message content it is plain text like any other unknown host, and the OS ingress fails it as `invalid-target` through the same null check as `buzz://join` or `buzz://unknown` instead of a dedicated refusal. The codec itself is gone from targets.ts: `SharedTarget`, `parseSharedTarget`, `bindSharedTarget`, `targetLink` and `parseTargetLink`, along with the `shared` format in buzz-links.ts and the `LocatorScope` type it existed for; `OpenTarget` is now the only target shape and `parseOpenTarget` binds scopes directly. Behaviour change: existing in-app `buzz://open` links in old messages stop opening and lose their preview and channel label, and `@buzz/author` no longer exports the `SharedTarget` type. No in-repo plugin imported it. The `#buzz=` browser address, `parseOpenTarget` and browser-history.ts are untouched; they share the JSON target shape, not the URL codec. Copy link already emitted `buzz://message`, so its comment is the only change there. The original Buzz desktop client never had this form. It was introduced in PR #18, refused at the OS boundary in PR #208, and is now removed. MessageLink and ReferenceText keep their message and channel handling with the type narrowing simplified; channelForLink/channelLinkLabel drop the scope parameter they only used for locator community checks. Link Lab demonstrates the same in-app links with `buzz://channel/general` and a `buzz://message` thread link, and docs/deep-links.md, docs/plugin-architecture.md and the Link Lab README describe unknown hosts as rejected everywhere rather than in-app only. One negative test per parser layer pins the removal with a literal `buzz://open?target=…` string: parseBuzzLink returns null, deepLinkStep fails `invalid-target`, message-link-parts leaves it as plain text, and InlineLink renders it as text. The open PR #401 adds a test in entity-navigation.test.tsx that calls bindSharedTarget/parseTargetLink/targetLink; it will conflict with this commit and needs rewriting against parseOpenTarget when it lands. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
wesbillman
left a comment
There was a problem hiding this comment.
No actionable findings in the unknown-parameter handling or locator removal; the supported links still bind through the existing navigation admission path, and retired locators become inert. Star Lord automated source review via Wes’s account: head fbc3c57f055641664c527e72365679dc8a7c30d9, base 5d2b08e2ff3bb40dc62f04015298ff319f4a4f8a. No tests or app execution; hosted CI was still running at the snapshot, and packaged deep-link delivery plus keyboard/focus recovery remain unverified.
| no community: they bind to the receiving conversation's community and viewer and | ||
| pass through existing navigation admission and session ownership checks. The app | ||
| has no link form of its own; any other `buzz://` host is rejected everywhere, | ||
| staying plain text in messages. Message targets open their |
There was a problem hiding this comment.
🤖 [P3] Distinguish unknown hosts from supported entity links
After listing only the channel/message forms, this passage says any other buzz:// host is rejected everywhere and stays plain text. Supported buzz://repo, buzz://project, buzz://pr, and buzz://issue links still pass through parseBuzzLink and are linkified/routed. For example, messageLinkParts("buzz://repo?owner=<valid-hex-owner>&d=r") returns a link part; the existing InlineLink test also expects repo links to have kind buzz.
Please use “any unknown buzz:// host” (as in docs/deep-links.md) or reference the full accepted-forms list so plugin authors are not told supported entity links are inert. The same wording needs correction in src/bundled/link-lab/README.md:35–37.
* origin/main: (27 commits) Let plugin pages publish NIP-AR artifacts and embed the host thread view (#434) test(app): migrate entity-navigation test off removed buzz://open locator API (#463) Show agent activity in navigation (#423) test(browser): hold motion when it commits, not on its start event (#459) fix(navigation): ignore unknown query parameters on Buzz links and remove the buzz://open locator (#457) feat(design-system): distinguish controls on floating surfaces (#429) feat(native): add community extras and media preparation (#450) Clone inventory identities through reviewed text and fresh identity creation (#289) feat(communities): add right-click actions to the community rail (#400) fix(messages): keep a send reveal pending until its scroll runs (#454) fix(messages): reserve a stable scrollbar gutter on the channel feed (#451) fix(sidebar): list plugin pages as sidebar rows via an opt-in primary flag (#401) feat(channels): surface canvas content in channel settings (#426) fix(profiles): remove redundant presence status row (#394) test(browser): count live retries once the page handles startup controls (#443) feat(composer): host-owned resource links for the Projects picker (#445) feat: support native read state and recent channel activity (#444) feat(native): serve relay media and uploads in packaged builds (#433) feat(channels): suggest joined channels in the composer (#446) feat: support native agent activity, library, memories, and community resolution (#441) ... Signed-off-by: Codex <noreply@openai.com>
Summary
Third deep-links slice: three commits on top of
mainat 5d2b08e.buzz://messagekeeps onlychannel,idandthread; thechannelforms ignore the whole query; entity hosts keep only their per-type keys, socommiton a project ortabon a PR/issue is dropped too. A duplicated known key such aschannel=a&channel=bis still ambiguous and rejects. This matches the original Buzz desktop client's lax message-link handling. Credentials, port, fragment, the length cap and the lowercase scheme requirement are unchanged. Everything rebuilt from a parsed link (entityHref, Copy link, the browser address) already emits the canonical form.buzz://project?…&tab=commits&commit=<hash>parses to the commits section with no hash, andentityHrefof the result is the canonical project link.buzz://open?target=locator codec (fbc3c57).SharedTarget,parseSharedTarget,bindSharedTarget,targetLink,parseTargetLinkand thesharedlink format are deleted, with no shim or flag.parseBuzzLinkreturns null forbuzz://open, so it is plain text in message content and the OS ingress fails it asinvalid-targetthrough the same null check as any other unknown host. The original Buzz client never had this form: it was introduced in Add navigation history and preserve Messages sidebar on return #18, refused at the OS boundary in feat(desktop): add Buzz deep links and read-only entity destinations #208, and is now removed. The#buzz=browser address,parseOpenTargetandbrowser-history.tsshare the JSON target shape, not the URL codec, and are untouched. Link Lab demonstrates the same in-app links withbuzz://channelandbuzz://messagesamples;docs/deep-links.md,docs/plugin-architecture.mdand the Link Lab README now describe unknown hosts as rejected everywhere rather than "in-app only".Behaviour change
buzz://openlinks in old messages stop opening and lose their preview and channel label.@buzz/authorno longer exports theSharedTargettype. No in-repo plugin imported it.Verification
tsc --noEmit,pnpm lintandpnpm checkare clean.tests/browser/buzz-links.spec.mjsandtests/browser/entity-destinations.spec.mjs: 5 passed.buzz://open?target=…string:parseBuzzLinkreturns null,deepLinkStepfailsinvalid-target,messageLinkPartsleaves it as plain text, andInlineLinkrenders it as text.src/,tests/,docs/and the README findsbuzz://openonly in those negative tests.Known follow-up
Open #401 adds a test in
src/app/entity-navigation.test.tsxthat callsbindSharedTarget(parseTargetLink(targetLink(…))). It will conflict with this branch and needs rewriting againstparseOpenTarget, whichever lands second.🤖 Generated with Claude Code