···44import { after } from "next/server";
55import { getLexClient } from "@/data/lex-client";
66import { generateTid } from "./tid";
77-import { loadCurrentUser } from "./queries";
77+import { loadCurrentUser, resolveHandleToDid } from "./queries";
88import { refresh } from "next/cache";
99import * as trail from "@/lib/lexicons/app/sidetrail/trail";
1010import * as walk from "@/lib/lexicons/app/sidetrail/walk";
···2222} from "@/data/db";
2323import { eq, and } from "drizzle-orm";
2424import { cidForLex } from "@atproto/lex-cbor";
2525+import { AtUri } from "@atproto/syntax";
25262627// ============================================================================
2728// Helpers
···3031function extractRkey(uri: string): string {
3132 const parts = uri.split("/");
3233 return parts[parts.length - 1];
3434+}
3535+3636+/**
3737+ * Resolves an at:// URI to use a DID instead of a handle.
3838+ * If the URI already uses a DID or is not an at:// URI, returns it unchanged.
3939+ */
4040+async function resolveAtUri(uri: string): Promise<string> {
4141+ if (!uri.startsWith("at://")) {
4242+ return uri;
4343+ }
4444+4545+ const parsed = new AtUri(uri);
4646+ if (parsed.host.startsWith("did:")) {
4747+ return uri;
4848+ }
4949+5050+ const did = await resolveHandleToDid(parsed.host);
5151+ return `at://${did}/${parsed.collection}/${parsed.rkey}`;
3352}
34533554// ============================================================================
···414433 }
415434416435 if (stop.external) {
436436+ const resolvedUri = await resolveAtUri(stop.external.uri);
417437 const external: trail.External = {
418418- uri: stop.external.uri as l.Uri,
438438+ uri: resolvedUri as l.Uri,
419439 };
420440 if (stop.external.title) {
421441 external.title = stop.external.title;