From fdc47549f4c2fcaaea1d73cc34c814a65e01c068 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Mon, 5 Oct 2026 02:05:48 +0900 Subject: [PATCH] web: change `/{issues,pulls}/[aturi]` to `/{issues,pulls}/[rkey]` Signed-off-by: Seongmin Lee --- web/src/hooks.test.ts | 27 ----------------- web/src/hooks.ts | 12 -------- web/src/lib/api/pullRoute.ts | 13 ++++----- .../repo/tickets/TicketCardContent.svelte | 5 ++-- .../routes/[handle]/[repo]/+layout@.svelte | 6 ++-- .../issues/{[aturi] => [rkey]}/+page.svelte | 0 .../issues/{[aturi] => [rkey]}/+page.ts | 29 +++++++++++-------- .../issues/{[aturi] => [rkey]}/issue.test.ts | 0 .../pulls/{[aturi] => [rkey]}/+layout.ts | 7 +++-- .../pulls/{[aturi] => [rkey]}/+page.svelte | 0 .../[repo]/pulls/{[aturi] => [rkey]}/+page.ts | 8 ++--- .../{[aturi] => [rkey]}/[version]/+layout.ts | 4 +-- .../[version]/[[range]]/+page.svelte | 2 +- .../[version]/[[range]]/+page.ts | 6 ++-- .../[[range]]/PullViewPage.stories.svelte | 0 .../[version]/[[range]]/PullViewPage.svelte | 9 +++--- 16 files changed, 46 insertions(+), 82 deletions(-) delete mode 100644 web/src/hooks.test.ts delete mode 100644 web/src/hooks.ts rename web/src/routes/[handle]/[repo]/issues/{[aturi] => [rkey]}/+page.svelte (100%) rename web/src/routes/[handle]/[repo]/issues/{[aturi] => [rkey]}/+page.ts (90%) rename web/src/routes/[handle]/[repo]/issues/{[aturi] => [rkey]}/issue.test.ts (100%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/+layout.ts (93%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/+page.svelte (100%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/+page.ts (61%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/[version]/+layout.ts (93%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/[version]/[[range]]/+page.svelte (91%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/[version]/[[range]]/+page.ts (94%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/[version]/[[range]]/PullViewPage.stories.svelte (100%) rename web/src/routes/[handle]/[repo]/pulls/{[aturi] => [rkey]}/[version]/[[range]]/PullViewPage.svelte (99%) diff --git a/web/src/hooks.test.ts b/web/src/hooks.test.ts deleted file mode 100644 index 440ffa3f1..000000000 --- a/web/src/hooks.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { reroute } from "./hooks"; - -const at = (path: string) => reroute({ url: new URL(`https://x${path}`), fetch }); - -describe("reroute", () => { - const encoded = encodeURIComponent("at://did:plc:abc/sh.tangled.repo.pull/3xyz"); - - it("encodes a raw at-uri", () => { - expect(at("/alice/repo/pulls/at://did:plc:abc/sh.tangled.repo.pull/3xyz/latest")).toBe( - `/alice/repo/pulls/${encoded}/latest` - ); - }); - - it("encodes a collapsed at-uri", () => { - expect(at("/alice/repo/pulls/at:/did:plc:abc/sh.tangled.repo.pull/3xyz")).toBe( - `/alice/repo/pulls/${encoded}` - ); - }); - - it("leaves encoded and unrelated urls alone", () => { - expect(at(`/alice/repo/pulls/${encoded}/1/a..b`)).toBe( - `/alice/repo/pulls/${encoded}/1/a..b` - ); - expect(at("/alice/repo/pulls")).toBe("/alice/repo/pulls"); - }); -}); diff --git a/web/src/hooks.ts b/web/src/hooks.ts deleted file mode 100644 index 5b0af2dc6..000000000 --- a/web/src/hooks.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Reroute } from "@sveltejs/kit"; - -// small hack to support raw at-uri as path segment: -// `/issues/at://did:example:repo/org.tangled.repo.ticket/123` -const RAW_ATURI = /\/(pulls|issues)\/at:\/\/?([^/]+)\/([^/]+)\/([^/]+)/; - -export const reroute: Reroute = ({ url }) => - url.pathname.replace( - RAW_ATURI, - (_match, section, authority, collection, rkey) => - `/${section}/${encodeURIComponent(`at://${authority}/${collection}/${rkey}`)}` - ); diff --git a/web/src/lib/api/pullRoute.ts b/web/src/lib/api/pullRoute.ts index a2b8e14c3..7f5533259 100644 --- a/web/src/lib/api/pullRoute.ts +++ b/web/src/lib/api/pullRoute.ts @@ -1,11 +1,10 @@ -// the pull page's url grammar, where goes in raw and `reroute` in -// src/hooks.ts folds its segments back together before routing: +// the pull page's url grammar: // -// /pulls//latest diff of the newest version -// /pulls//1 diff of version 1 -// /pulls//1/c1..c2 that diff narrowed to a commit range -// /pulls//0..1 interdiff between two versions -// /pulls//0..1/ that interdiff narrowed to one change +// /pulls//latest diff of the newest version +// /pulls//1 diff of version 1 +// /pulls//1/c1..c2 that diff narrowed to a commit range +// /pulls//0..1 interdiff between two versions +// /pulls//0..1/ that interdiff narrowed to one change export interface Revspec { base: string; diff --git a/web/src/lib/components/repo/tickets/TicketCardContent.svelte b/web/src/lib/components/repo/tickets/TicketCardContent.svelte index f115e66bf..757030de5 100644 --- a/web/src/lib/components/repo/tickets/TicketCardContent.svelte +++ b/web/src/lib/components/repo/tickets/TicketCardContent.svelte @@ -1,6 +1,5 @@ diff --git a/web/src/routes/[handle]/[repo]/+layout@.svelte b/web/src/routes/[handle]/[repo]/+layout@.svelte index 6cb1f4cc8..4c6d4ca89 100644 --- a/web/src/routes/[handle]/[repo]/+layout@.svelte +++ b/web/src/routes/[handle]/[repo]/+layout@.svelte @@ -108,8 +108,8 @@ }); const isCustomOgChildRoute = $derived( - (page.route.id ?? "").includes("/issues/[aturi]") || - (page.route.id ?? "").includes("/pulls/[aturi]") + (page.route.id ?? "").includes("/issues/[rkey]") || + (page.route.id ?? "").includes("/pulls/[rkey]") ); const activeTab = $derived.by(() => { @@ -120,7 +120,7 @@ }); // the pull page is full screen view - const bare = $derived((page.route.id ?? "").startsWith("/[handle]/[repo]/pulls/[aturi]")); + const bare = $derived((page.route.id ?? "").startsWith("/[handle]/[repo]/pulls/[rkey]")); const standalone = $derived((page.route.id ?? "").endsWith("/fork")); // commit and pull pages break out of the reading column, everything else diff --git a/web/src/routes/[handle]/[repo]/issues/[aturi]/+page.svelte b/web/src/routes/[handle]/[repo]/issues/[rkey]/+page.svelte similarity index 100% rename from web/src/routes/[handle]/[repo]/issues/[aturi]/+page.svelte rename to web/src/routes/[handle]/[repo]/issues/[rkey]/+page.svelte diff --git a/web/src/routes/[handle]/[repo]/issues/[aturi]/+page.ts b/web/src/routes/[handle]/[repo]/issues/[rkey]/+page.ts similarity index 90% rename from web/src/routes/[handle]/[repo]/issues/[aturi]/+page.ts rename to web/src/routes/[handle]/[repo]/issues/[rkey]/+page.ts index 1921738d8..608eb836e 100644 --- a/web/src/routes/[handle]/[repo]/issues/[aturi]/+page.ts +++ b/web/src/routes/[handle]/[repo]/issues/[rkey]/+page.ts @@ -1,5 +1,5 @@ import { browser } from "$app/environment"; -import { isResourceUri } from "@atcute/lexicons/syntax"; +import { isRecordKey } from "@atcute/lexicons/syntax"; import { error, isHttpError } from "@sveltejs/kit"; import { createBobbinClient, ClientResponseError, type BobbinContext } from "$lib/api/client"; import { REACTION_AUTHOR_DOCS } from "$lib/api/descriptors"; @@ -148,9 +148,9 @@ const loadThread = async ( export const load: PageLoad = async (event) => { const parent = await event.parent(); - const uri = event.params.aturi; + const rkey = event.params.rkey; - if (!isResourceUri(uri)) error(404, "Issue not found"); + if (!isRecordKey(rkey)) error(404, "Issue not found"); const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, @@ -158,15 +158,20 @@ export const load: PageLoad = async (event) => { }); const viewerDid = parent.auth?.did; - const ticket = getTicketView(ctx, uri).catch((cause: unknown) => { - if ( - cause instanceof ClientResponseError && - (cause.status === 404 || httpStatusFor(cause) === 404) - ) { - return null; - } - throw cause; - }); + const ticket = Promise.resolve(parent.repo) + .then((repo) => { + if (!repo.repoDid) error(500, "Repository has no DID"); + return getTicketView(ctx, `at://${repo.repoDid}/org.tangled.track.ticket/${rkey}`); + }) + .catch((cause: unknown) => { + if ( + cause instanceof ClientResponseError && + (cause.status === 404 || httpStatusFor(cause) === 404) + ) { + return null; + } + throw cause; + }); const page = loadThread( ctx, diff --git a/web/src/routes/[handle]/[repo]/issues/[aturi]/issue.test.ts b/web/src/routes/[handle]/[repo]/issues/[rkey]/issue.test.ts similarity index 100% rename from web/src/routes/[handle]/[repo]/issues/[aturi]/issue.test.ts rename to web/src/routes/[handle]/[repo]/issues/[rkey]/issue.test.ts diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/+layout.ts b/web/src/routes/[handle]/[repo]/pulls/[rkey]/+layout.ts similarity index 93% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/+layout.ts rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/+layout.ts index e71fb445d..b38138630 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/+layout.ts +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/+layout.ts @@ -1,5 +1,5 @@ import { browser } from "$app/environment"; -import { isResourceUri } from "@atcute/lexicons/syntax"; +import { isRecordKey } from "@atcute/lexicons/syntax"; import { error } from "@sveltejs/kit"; import { createBobbinClient } from "$lib/api/client"; import { COMMENT_AUTHOR_DOCS } from "$lib/api/descriptors"; @@ -15,14 +15,15 @@ import type { LayoutLoad } from "./$types"; export const load: LayoutLoad = async (event) => { const parent = await event.parent(); - const uri = event.params.aturi; - if (!isResourceUri(uri)) error(404, "Pull request not found"); + const rkey = event.params.rkey; + if (!isRecordKey(rkey)) error(404, "Pull request not found"); const pullPage = (async () => { const repo = await parent.repo; const defaultBranch = await repo.defaultBranch; const repoDid = repo.repoDid; if (!repoDid) error(404, "Pull request not found"); + const uri = `at://${repoDid}/org.tangled.track.ticket/${rkey}`; const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/+page.svelte b/web/src/routes/[handle]/[repo]/pulls/[rkey]/+page.svelte similarity index 100% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/+page.svelte rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/+page.svelte diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/+page.ts b/web/src/routes/[handle]/[repo]/pulls/[rkey]/+page.ts similarity index 61% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/+page.ts rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/+page.ts index 325279cbc..b3203548e 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/+page.ts +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/+page.ts @@ -1,12 +1,12 @@ import { error, redirect } from "@sveltejs/kit"; -import { isResourceUri } from "@atcute/lexicons/syntax"; +import { isRecordKey } from "@atcute/lexicons/syntax"; import type { PageLoad } from "./$types"; // every diff lives under a version segment, so the bare pull url picks one export const load: PageLoad = (event) => { - const uri = event.params.aturi; + const rkey = event.params.rkey; - if (!isResourceUri(uri)) error(404, "Pull request not found"); + if (!isRecordKey(rkey)) error(404, "Pull request not found"); - redirect(307, `/${event.params.handle}/${event.params.repo}/pulls/${uri}/latest`); + redirect(307, `/${event.params.handle}/${event.params.repo}/pulls/${rkey}/latest`); }; diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/+layout.ts b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/+layout.ts similarity index 93% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/+layout.ts rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/+layout.ts index c79fb75ae..dabac7397 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/+layout.ts +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/+layout.ts @@ -18,8 +18,8 @@ export const load: LayoutLoad = async (event) => { ? parseInterdiffRoute(pull.versions, event.params.version) : parseDiffRoute(pull.versions, event.params.version); if (isRedirect(route)) { - const { handle, repo, aturi } = event.params; - const redirectTo = `/${handle}/${repo}/pulls/${aturi}/latest`; + const { handle, repo, rkey } = event.params; + const redirectTo = `/${handle}/${repo}/pulls/${rkey}/latest`; if (!browser) redirect(307, redirectTo); return { redirectTo }; } diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.svelte b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.svelte similarity index 91% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.svelte rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.svelte index b97f450ed..d590c2e77 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.svelte +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.svelte @@ -6,7 +6,7 @@ import Bones from "$lib/components/ui/Bones.svelte"; import Pending from "$lib/components/ui/Pending.svelte"; import repoPullsPullviewpageSkeletonFixture from "$lib/bones/repo-pulls-pullviewpage--skeleton-fixture.bones.json"; - import PullViewPage from "$routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte"; + import PullViewPage from "$routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.svelte"; type LoadedPullViewData = Awaited["data"]>; diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.ts b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.ts similarity index 94% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.ts rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.ts index 02c3ec727..f912fc5a9 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/+page.ts +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/+page.ts @@ -21,8 +21,8 @@ export const load: PageLoad = async (event) => { if (isRedirect(route)) { // the layout already vetted the version against the same parser, so the range is // the only thing left that can be bad -- drop it and keep the version - const { handle, repo, aturi, version } = event.params; - const redirectTo = `/${handle}/${repo}/pulls/${aturi}/${version}`; + const { handle, repo, rkey, version } = event.params; + const redirectTo = `/${handle}/${repo}/pulls/${rkey}/${version}`; if (!browser) redirect(307, redirectTo); return { redirectTo }; } @@ -68,7 +68,7 @@ export const load: PageLoad = async (event) => { return { ...versionPage, view: route, - uri: event.params.aturi + uri: pull.uri }; }); diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.stories.svelte b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.stories.svelte similarity index 100% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.stories.svelte rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.stories.svelte diff --git a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.svelte similarity index 99% rename from web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte rename to web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.svelte index 7aec50eb3..65484b490 100644 --- a/web/src/routes/[handle]/[repo]/pulls/[aturi]/[version]/[[range]]/PullViewPage.svelte +++ b/web/src/routes/[handle]/[repo]/pulls/[rkey]/[version]/[[range]]/PullViewPage.svelte @@ -48,7 +48,6 @@ import Ticket from "$lib/components/repo/tickets/Ticket.svelte"; import type { Person } from "$lib/components/repo/tickets/TicketInfoBar.svelte"; import Card from "$lib/components/ui/Card.svelte"; - import type { ResolvedPathname } from "$app/types"; import type { Did } from "@atcute/lexicons/syntax"; import type { TicketState } from "$lib/api/records"; import { commitEmbedRecord, type CommentView } from "$lib/components/comment/comments"; @@ -208,11 +207,11 @@ const short = (hash: string) => hash.slice(0, 8); - // the at-uri sits outside `resolve`, which would drop the empty segment in `at://` let pullsBase = $derived(resolve(`/${data.repo.ownerHandle}/${data.repo.name}/pulls` as "/")); - let href = $derived( - (version: number | string, change?: string) => - `${pullsBase}/${data.uri}/${version}${change ? `/${change}` : ""}` as ResolvedPathname + let href = $derived((version: number | string, change?: string) => + resolve( + `/${data.repo.ownerHandle}/${data.repo.name}/pulls/${pull.rkey}/${version}${change ? `/${change}` : ""}` as "/" + ) ); const versionRange = $derived({ start: view.mode === "diff" ? view.version : view.oldVersion, -- 2.51.2