Skip to content

Commit

Permalink
Big ol' route restructure (#116)
Browse files Browse the repository at this point in the history
* Big ol' route restructure

* Dont share params
  • Loading branch information
tom-sherman authored Aug 29, 2024
1 parent 1988c58 commit 936c332
Show file tree
Hide file tree
Showing 16 changed files with 846 additions and 723 deletions.
6 changes: 4 additions & 2 deletions packages/atproto-browser/app/actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use server";

import { getAtUriPath } from "@/lib/util";
import { AtUri } from "@atproto/syntax";
import { redirect } from "next/navigation";

export async function navigateUri(_state: unknown, formData: FormData) {
const uri = formData.get("uri") as string;
redirect(`/at?u=${uri}`);
const uri = new AtUri(formData.get("uri") as string);
redirect(getAtUriPath(uri));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { JSONType, JSONValue } from "@/app/at/_lib/atproto-json";
import { resolveIdentity } from "@/lib/atproto-server";
import { getHandle, getKey, getPds } from "@atproto/identity";
import { verifyRecords } from "@atproto/repo";
import { Suspense } from "react";

export default async function RkeyPage({
params,
}: {
params: {
identifier: string;
collection: string;
rkey: string;
};
}) {
const identityResult = await resolveIdentity(params.identifier);
if (!identityResult.success) {
return <div>{identityResult.error}</div>;
}
const didDocument = identityResult.identity;
const handle = getHandle(didDocument);
if (!handle) {
return <div>No handle found for DID: {didDocument.id}</div>;
}
const pds = getPds(didDocument);
if (!pds) {
return <div>No PDS found for DID: {didDocument.id}</div>;
}

const getRecordUrl = new URL(`${pds}/xrpc/com.atproto.repo.getRecord`);
getRecordUrl.searchParams.set("repo", didDocument.id);
getRecordUrl.searchParams.set("collection", params.collection);
getRecordUrl.searchParams.set("rkey", params.rkey);

const response = await fetch(getRecordUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (!response.ok) {
return (
<div>
Failed to fetch record: {response.statusText}. URL:{" "}
{getRecordUrl.toString()}
</div>
);
}

const record = (await response.json()) as JSONType;

return (
<>
<h2>
Record
<Suspense
fallback={
<span title="Verifying record..." aria-busy>
🤔
</span>
}
>
<RecordVerificationBadge
did={didDocument.id}
collection={params.collection}
rkey={params.rkey}
/>
</Suspense>
</h2>
<JSONValue data={record} repo={didDocument.id} />
</>
);
}

async function RecordVerificationBadge({
did,
collection,
rkey,
}: {
did: string;
collection: string;
rkey: string;
}) {
const identityResult = await resolveIdentity(did);
if (!identityResult.success) {
throw new Error(identityResult.error);
}
const didDoc = identityResult.identity;
const pds = getPds(didDoc);
if (!pds) {
return <span title="Invalid record (no pds)"></span>;
}

const verifyRecordsUrl = new URL(`${pds}/xrpc/com.atproto.sync.getRecord`);
verifyRecordsUrl.searchParams.set("did", did);
verifyRecordsUrl.searchParams.set("collection", collection);
verifyRecordsUrl.searchParams.set("rkey", rkey);

const response = await fetch(verifyRecordsUrl, {
headers: {
accept: "application/vnd.ipld.car",
},
});

if (!response.ok) {
return (
<span title={`Invalid record (failed to fetch ${await response.text()})`}>
</span>
);
}
const car = new Uint8Array(await response.arrayBuffer());
const key = getKey(didDoc);
if (!key) {
return <span title="Invalid record (no key)"></span>;
}

try {
await verifyRecords(car, did, key);
return <span title="Valid record">🔒</span>;
} catch (e) {
if (e instanceof Error) {
return <span title={`Invalid record (${e.message})`}></span>;
} else {
return <span title="Invalid record (unknown)"></span>;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { resolveIdentity } from "@/lib/atproto-server";
import { getHandle, getPds } from "@atproto/identity";
import Link from "next/link";
import { Suspense } from "react";
import { DidSummary } from "@/app/at/_lib/did-components";

export default async function Layout({
children,
params,
}: {
children: React.ReactNode;
params: { identifier: string };
}) {
const identityResult = await resolveIdentity(params.identifier);
if (!identityResult.success) {
return <div>{identityResult.error}</div>;
}
const didDocument = identityResult.identity;
const handle = getHandle(didDocument);
if (!handle) {
return <div>No handle found for DID: {didDocument.id}</div>;
}
const pds = getPds(didDocument);
if (!pds) {
return <div>No PDS found for DID: {didDocument.id}</div>;
}

return (
<div>
<details>
<summary>
Author: {handle} (
<Link href={`/at/${didDocument.id}`}>{didDocument.id}</Link>)
</summary>
<Suspense>
<DidSummary did={didDocument.id} />
</Suspense>
</details>

{children}
</div>
);
}
59 changes: 59 additions & 0 deletions packages/atproto-browser/app/at/[identifier]/[collection]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { listRecords } from "@/lib/atproto";
import { resolveIdentity } from "@/lib/atproto-server";
import { getHandle, getPds } from "@atproto/identity";
import Link from "next/link";
import { SWRConfig } from "swr";
import { CollectionItems } from "../../_lib/collection";

export default async function CollectionPage({
params,
}: {
params: { identifier: string; collection: string };
}) {
const identityResult = await resolveIdentity(params.identifier);
if (!identityResult.success) {
return <div>{identityResult.error}</div>;
}
const didDocument = identityResult.identity;
const handle = getHandle(didDocument);
if (!handle) {
return <div>No handle found for DID: {didDocument.id}</div>;
}
const pds = getPds(didDocument);
if (!pds) {
return <div>No PDS found for DID: {didDocument.id}</div>;
}

const fetchKey =
`listCollections/collection:${params.collection}/cursor:none` as const;

return (
<div>
<h1>
{handle}&apos;s {params.collection} records{" "}
<Link
href={`/collection-rss?u=at://${params.identifier}/${params.collection}</h1>}`}
title="RSS feed"
>
🛜
</Link>
</h1>
<ul>
<SWRConfig
value={{
fallback: {
[fetchKey]: listRecords(pds, didDocument.id, params.collection),
},
}}
>
<CollectionItems
collection={params.collection}
pds={pds}
repo={didDocument.id}
fetchKey={fetchKey}
/>
</SWRConfig>
</ul>
</div>
);
}
Loading

0 comments on commit 936c332

Please sign in to comment.