Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate frontpage post to be lexicon first #199

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions packages/frontpage/app/(app)/_components/post-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { getVoteForPost } from "@/lib/data/db/vote";
import { ensureUser, getUser } from "@/lib/data/user";
import { TimeAgo } from "@/lib/components/time-ago";
import { VoteButton } from "./vote-button";
import { PostCollection, deletePost } from "@/lib/data/atproto/post";
import { getVerifiedHandle } from "@/lib/data/atproto/identity";
import { UserHoverCard } from "@/lib/components/user-hover-card";
import type { DID } from "@/lib/data/atproto/did";
Expand All @@ -15,6 +14,7 @@ import { revalidatePath } from "next/cache";
import { ReportDialogDropdownButton } from "./report-dialog";
import { DeleteButton } from "./delete-button";
import { ShareDropdownButton } from "./share-button";
import { atprotoClient, nsids } from "@/lib/data/atproto/repo";

type PostProps = {
id: number;
Expand Down Expand Up @@ -59,7 +59,7 @@ export async function PostCard({
subjectAuthorDid: author,
subjectCid: cid,
subjectRkey: rkey,
subjectCollection: PostCollection,
subjectCollection: nsids.FyiUnravelFrontpagePost,
});
}}
unvoteAction={async () => {
Expand Down Expand Up @@ -147,7 +147,10 @@ export async function PostCard({
export async function deletePostAction(rkey: string) {
"use server";
await ensureUser();
await deletePost(rkey);
const atproto = atprotoClient();
await atproto.fyi.unravel.frontpage.post.delete({
rkey,
});
Comment on lines +151 to +153
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is essentialy untyped because of a bug in the lex-cli generated code. See bluesky-social/atproto#2952

I'll probably leave this in draft until a solution is found for that.


revalidatePath("/");
}
Expand All @@ -170,9 +173,9 @@ export async function reportPostAction(

await createReport({
...formResult.data,
subjectUri: `at://${input.author}/${PostCollection}/${input.rkey}`,
subjectUri: `at://${input.author}/${nsids.FyiUnravelFrontpagePost}/${input.rkey}`,
subjectDid: input.author,
subjectCollection: PostCollection,
subjectCollection: nsids.FyiUnravelFrontpagePost,
subjectRkey: input.rkey,
subjectCid: input.cid,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import { UserHandle } from "./user-handle";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { CommentCollection } from "@/lib/data/atproto/comment";
import { PostCollection } from "@/lib/data/atproto/post";
import { getPostFromComment } from "@/lib/data/db/post";
import { getCommentLink, getPostLink } from "@/lib/navigation";
import { nsids } from "@/lib/data/atproto/repo";

const createLink = async (
collection?: string | null,
author?: DID | null,
rkey?: string | null,
) => {
switch (collection) {
case PostCollection:
case nsids.FyiUnravelFrontpagePost:
return getPostLink({ handleOrDid: author!, rkey: rkey! });

case CommentCollection:
Expand Down
8 changes: 4 additions & 4 deletions packages/frontpage/app/(app)/moderation/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
ModerationEventDTO,
createModerationEvent,
} from "@/lib/data/db/moderation";
import { PostCollection } from "@/lib/data/atproto/post";
import { CommentCollection } from "@/lib/data/atproto/comment";
import { revalidatePath } from "next/cache";
import Link from "next/link";
Expand All @@ -26,6 +25,7 @@ import { moderatePost } from "@/lib/data/db/post";
import { DID } from "@/lib/data/atproto/did";
import { moderateComment } from "@/lib/data/db/comment";
import { moderateUser } from "@/lib/data/db/user";
import { nsids } from "@/lib/data/atproto/repo";

export async function performModerationAction(
input: { reportId: number; status: "accepted" | "rejected" },
Expand All @@ -49,8 +49,8 @@ export async function performModerationAction(
};

if (report.subjectCollection) {
if (report.subjectCollection === PostCollection) {
newModEvent.subjectCollection = PostCollection;
if (report.subjectCollection === nsids.FyiUnravelFrontpagePost) {
newModEvent.subjectCollection = nsids.FyiUnravelFrontpagePost;
} else if (report.subjectCollection === CommentCollection) {
newModEvent.subjectCollection = CommentCollection;
}
Expand All @@ -61,7 +61,7 @@ export async function performModerationAction(

const modAction = async () => {
switch (report.subjectCollection) {
case PostCollection:
case nsids.FyiUnravelFrontpagePost:
return await moderatePost({
rkey: report.subjectRkey!,
authorDid: report.subjectDid! as DID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Metadata } from "next";
import { getVerifiedHandle } from "@/lib/data/atproto/identity";
import { PostPageParams, getPostPageData } from "./_lib/page-data";
import { LinkAlternateAtUri } from "@/lib/components/link-alternate-at";
import { PostCollection } from "@/lib/data/atproto/post";
import { nsids } from "@/lib/data/atproto/repo";

export async function generateMetadata(props: {
params: Promise<PostPageParams>;
Expand Down Expand Up @@ -47,7 +47,7 @@ export default async function Post(props: { params: Promise<PostPageParams> }) {
<>
<LinkAlternateAtUri
authority={authorDid}
collection={PostCollection}
collection={nsids.FyiUnravelFrontpagePost}
rkey={post.rkey}
/>
{post.status === "live" ? (
Expand Down
20 changes: 16 additions & 4 deletions packages/frontpage/app/(app)/post/new/_action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import { DID } from "@/lib/data/atproto/did";
import { getVerifiedHandle } from "@/lib/data/atproto/identity";
import { createPost } from "@/lib/data/atproto/post";
import { atprotoClient } from "@/lib/data/atproto/repo";
import { uncached_doesPostExist } from "@/lib/data/db/post";
import { DataLayerError } from "@/lib/data/error";
import { ensureUser } from "@/lib/data/user";
import { AtUri } from "@atproto/syntax";
import { redirect } from "next/navigation";

export async function newPostAction(_prevState: unknown, formData: FormData) {
Expand All @@ -26,13 +27,24 @@ export async function newPostAction(_prevState: unknown, formData: FormData) {
return { error: "Invalid URL" };
}

const atproto = atprotoClient();

try {
const { rkey } = await createPost({ title, url });
const record = await atproto.fyi.unravel.frontpage.post.create(
{},
{
title,
url,
createdAt: new Date().toISOString(),
},
);
const uri = new AtUri(record.uri);

const [handle] = await Promise.all([
getVerifiedHandle(user.did),
waitForPost(user.did, rkey),
waitForPost(user.did, uri.rkey),
]);
redirect(`/post/${handle}/${rkey}`);
redirect(`/post/${handle}/${uri.rkey}`);
} catch (error) {
if (!(error instanceof DataLayerError)) throw error;
return { error: "Failed to create post" };
Expand Down
17 changes: 8 additions & 9 deletions packages/frontpage/app/api/receive_hook/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { db } from "@/lib/db";
import * as schema from "@/lib/schema";
import { atprotoGetRecord } from "@/lib/data/atproto/record";
import { Commit } from "@/lib/data/atproto/event";
import * as atprotoPost from "@/lib/data/atproto/post";
import * as dbPost from "@/lib/data/db/post";
import * as atprotoComment from "@/lib/data/atproto/comment";
import { VoteRecord } from "@/lib/data/atproto/vote";
Expand All @@ -17,6 +16,7 @@ import {
unauthed_createCommentVote,
} from "@/lib/data/db/vote";
import { unauthed_createNotification } from "@/lib/data/db/notification";
import { atprotoClient, nsids } from "@/lib/data/atproto/repo";

export async function POST(request: Request) {
const auth = request.headers.get("Authorization");
Expand All @@ -36,24 +36,23 @@ export async function POST(request: Request) {
throw new Error("No AtprotoPersonalDataServer service found");
}

const atproto = atprotoClient(service);

const promises = ops.map(async (op) => {
const { collection, rkey } = op.path;
console.log("Processing", collection, rkey, op.action);

if (collection === atprotoPost.PostCollection) {
if (collection === nsids.FyiUnravelFrontpagePost) {
if (op.action === "create") {
const record = await atprotoGetRecord({
serviceEndpoint: service,
const postRecord = await atproto.fyi.unravel.frontpage.post.get({
repo,
collection,
rkey,
});
const postRecord = atprotoPost.PostRecord.parse(record.value);
await dbPost.unauthed_createPost({
post: postRecord,
post: postRecord.value,
rkey,
authorDid: repo,
cid: record.cid,
cid: postRecord.cid,
offset: seq,
});
} else if (op.action === "delete") {
Expand Down Expand Up @@ -108,7 +107,7 @@ export async function POST(request: Request) {

if (
hydratedVoteRecordValue.subject.uri.collection ===
atprotoPost.PostCollection
nsids.FyiUnravelFrontpagePost
) {
await unauthed_createPostVote({
repo,
Expand Down
2 changes: 1 addition & 1 deletion packages/frontpage/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ export async function importDpopJwks({
}

export async function fetchAuthenticatedAtproto(
input: RequestInfo,
input: string | Request | URL,
init?: RequestInit,
) {
const session = await getSession();
Expand Down
6 changes: 3 additions & 3 deletions packages/frontpage/lib/data/atproto/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
import { createAtUriParser } from "./uri";
import { DataLayerError } from "../error";
import { z } from "zod";
import { PostCollection } from "./post";
import { DID, getPdsUrl } from "./did";
import { MAX_COMMENT_LENGTH } from "../db/constants";
import { nsids } from "./repo";

export const CommentCollection = "fyi.unravel.frontpage.comment";

Expand All @@ -23,7 +23,7 @@ export const CommentRecord = z.object({
.optional(),
post: z.object({
cid: z.string(),
uri: createAtUriParser(z.literal(PostCollection)),
uri: createAtUriParser(z.literal(nsids.FyiUnravelFrontpagePost)),
}),
createdAt: z.string(),
});
Expand All @@ -49,7 +49,7 @@ export async function createComment({ parent, post, content }: CommentInput) {
: undefined,
post: {
cid: post.cid,
uri: `at://${post.authorDid}/${PostCollection}/${post.rkey}`,
uri: `at://${post.authorDid}/${nsids.FyiUnravelFrontpagePost}/${post.rkey}`,
},
createdAt: new Date().toISOString(),
};
Expand Down
4 changes: 2 additions & 2 deletions packages/frontpage/lib/data/atproto/event.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import "server-only";
import { z } from "zod";
import { CommentCollection } from "./comment";
import { PostCollection } from "./post";
import { isDid } from "./did";
import { nsids } from "./repo";

// This module refers to the event emitted by the Firehose

export const Collection = z.union([
z.literal(PostCollection),
z.literal(nsids.FyiUnravelFrontpagePost),
z.literal(CommentCollection),
z.literal("fyi.unravel.frontpage.vote"),
]);
Expand Down
68 changes: 0 additions & 68 deletions packages/frontpage/lib/data/atproto/post.ts

This file was deleted.

25 changes: 25 additions & 0 deletions packages/frontpage/lib/data/atproto/repo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AtpBaseClient } from "@repo/frontpage-atproto-client";
import { getUser } from "../user";
import { fetchAuthenticatedAtproto } from "@/lib/auth";
import { cache } from "react";

export { ids as nsids } from "@repo/frontpage-atproto-client/lexicons";

export const atprotoClient = cache(
(service?: string) =>
new AtpBaseClient(async (url: string, init: RequestInit) => {
const user = await getUser();
const s = service ?? user?.pdsUrl;
if (!s) {
throw new Error("No service url");
}

const u = new URL(url, s);

if (user) {
return fetchAuthenticatedAtproto(u, init);
}

return fetch(u, init);
}),
);
4 changes: 2 additions & 2 deletions packages/frontpage/lib/data/atproto/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import "server-only";
import { ensureUser } from "../user";
import { atprotoCreateRecord, atprotoDeleteRecord } from "./record";
import { z } from "zod";
import { PostCollection } from "./post";
import { CommentCollection } from "./comment";
import { DID } from "./did";
import { createAtUriParser } from "./uri";
import { nsids } from "./repo";

const VoteSubjectCollection = z.union([
z.literal(PostCollection),
z.literal(nsids.FyiUnravelFrontpagePost),
z.literal(CommentCollection),
]);

Expand Down
Loading