fix(links): finish the /p/ permalink migration — emit canonical links everywhere, teach the viewer router to parse them#213
Merged
Conversation
…r router to parse them /p/ links were half-implemented in 0.11.0: the server resolved them but the viewer's History-API router only parsed /s/ shapes, so canonical links from publish_post landed on the workspace instead of the post. The router now parses both spellings and writes /p/; the CLI, viewer copy-link/open-as-image, OG/canonical meta tags, screenshot worker, and all MCP tool responses (including deprecated aliases) now emit /p/. Legacy /s/ URLs remain accepted inbound. Adds a /p/:id standalone e2e regression test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
/p/permalinks were half-implemented in 0.11.0. PR #140 added the/p/:idserver routes and made the newpublish_postMCP tool emit them — but the viewer's History-API router was never taught to parse them. The result: the server resolves a/p/link fine (byte-identical response to/s/), the SPA shell loads… and then the client-side router matches nothing, so the user lands on the workspace instead of the post. To anyone clicking an agent-shared/p/link, the post simply "doesn't resolve."Reproduced against a live 0.11.0 deployment — the deployed bundle's router only contains:
Meanwhile, most of the app still emitted legacy
/s/links anyway (CLI, viewer copy-link, meta tags), so the canonical shape was both broken on arrival and barely used.The fix
Parse both, write canonical. The viewer router (
viewer/src/host.ts) now parses/[sp]/:idand/session/:id/[sp]/:pidinbound, and writes the canonical/p/shapes.Every link emitter now produces
/p/:bin/sideshow.js— CLIpublish/updateoutput URLserver/mcpHttp.ts+mcp/server.ts— all MCP tool responses, including the deprecatedpublish_surface/publish_snippetaliases (the deprecation is about tool names/args; the returned link can be canonical).postResult()loses itssegparam since there's only one answer now.viewer/src/api.ts— copy-link (postLink) and open-as-image (postImageLink)server/app.ts—<link rel="canonical">andog:url/og:imagepreview tagsworkers/screenshot.ts— the PNG matcher accepts both/p/:id.pngand/s/:id.png, so existing/s/share links keep their previewsNothing inbound changes:
/s/:id,/session/:id/s/:pid, and/s/:id.pngremain accepted as legacy aliases and resolve exactly as before. Card iframes still load surfaces from/s/:id?part=N(internal wire, not a user-facing link).Tests
goto /p/:idrenders the standalone full-page post — the exact scenario that shipped broken (the suite previously only covered/s/:id, which is how this slipped through)./s/gotos, deep-link[sp]tolerance).tsc --noEmit, oxlint.Changeset included (patch).