From 96eb6239214898873ee028a3138b8ab4a1959a29 Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Thu, 30 Apr 2026 15:13:33 -0400 Subject: [PATCH] use standard.site recommend records --- .../[rkey]/Interactions/recommendAction.ts | 25 +++--- appview/index.ts | 26 ++++++ lexicons/api/index.ts | 87 +++++++++++++++++++ lexicons/api/lexicons.ts | 28 ++++++ 4 files changed, 156 insertions(+), 10 deletions(-) diff --git a/app/lish/[did]/[publication]/[rkey]/Interactions/recommendAction.ts b/app/lish/[did]/[publication]/[rkey]/Interactions/recommendAction.ts index c219720c..c5d7e711 100644 --- a/app/lish/[did]/[publication]/[rkey]/Interactions/recommendAction.ts +++ b/app/lish/[did]/[publication]/[rkey]/Interactions/recommendAction.ts @@ -1,6 +1,6 @@ "use server"; -import { AtpBaseClient, PubLeafletInteractionsRecommend } from "lexicons/api"; +import { AtpBaseClient, SiteStandardGraphRecommend } from "lexicons/api"; import { getIdentityData } from "actions/getIdentityData"; import { restoreOAuthSession, OAuthSessionError } from "src/atproto-oauth"; import { TID } from "@atproto/common"; @@ -45,19 +45,19 @@ export async function recommendAction(args: { credentialSession.fetchHandler.bind(credentialSession), ); - let record: Un$Typed = { - subject: args.document, + let record: Un$Typed = { + document: args.document, createdAt: new Date().toISOString(), }; let rkey = TID.nextStr(); let uri = AtUri.make( credentialSession.did!, - "pub.leaflet.interactions.recommend", + "site.standard.graph.recommend", rkey, ); - await agent.pub.leaflet.interactions.recommend.create( + await agent.site.standard.graph.recommend.create( { rkey, repo: credentialSession.did! }, record, ); @@ -67,7 +67,7 @@ export async function recommendAction(args: { document: args.document, recommender_did: credentialSession.did!, record: { - $type: "pub.leaflet.interactions.recommend", + $type: "site.standard.graph.recommend", ...record, } as unknown as Json, }); @@ -139,10 +139,15 @@ export async function unrecommendAction(args: { let uri = new AtUri(existingRecommend.uri); - await agent.pub.leaflet.interactions.recommend.delete({ - rkey: uri.rkey, - repo: credentialSession.did!, - }); + // Delete from both collections (old and new schema) - one or both may exist + await Promise.all([ + agent.site.standard.graph.recommend + .delete({ rkey: uri.rkey, repo: credentialSession.did! }) + .catch(() => {}), + agent.pub.leaflet.interactions.recommend + .delete({ rkey: uri.rkey, repo: credentialSession.did! }) + .catch(() => {}), + ]); await supabaseServerClient .from("recommends_on_documents") diff --git a/appview/index.ts b/appview/index.ts index 2cba2277..782ad144 100644 --- a/appview/index.ts +++ b/appview/index.ts @@ -15,6 +15,7 @@ import { SiteStandardDocument, SiteStandardPublication, SiteStandardGraphSubscription, + SiteStandardGraphRecommend, } from "lexicons/api"; import { AppBskyEmbedExternal, @@ -55,6 +56,7 @@ async function main() { ids.SiteStandardDocument, ids.SiteStandardPublication, ids.SiteStandardGraphSubscription, + ids.SiteStandardGraphRecommend, "parts.page.mention.service", "parts.page.mention.config", ], @@ -341,6 +343,30 @@ async function handleEvent(evt: Event) { } } + // site.standard.graph.recommend records go into the main "recommends_on_documents" table + if (evt.collection === ids.SiteStandardGraphRecommend) { + if (evt.event === "create" || evt.event === "update") { + let record = SiteStandardGraphRecommend.validateRecord(evt.record); + if (!record.success) return; + await supabase + .from("identities") + .upsert({ atp_did: evt.did }, { onConflict: "atp_did" }); + let { error } = await supabase.from("recommends_on_documents").upsert({ + uri: evt.uri.toString(), + recommender_did: evt.did, + document: record.value.document, + record: record.value as Json, + }); + if (error) console.log("Error upserting recommend:", error); + } + if (evt.event === "delete") { + await supabase + .from("recommends_on_documents") + .delete() + .eq("uri", evt.uri.toString()); + } + } + // site.standard.graph.subscription records go into the main "publication_subscriptions" table if (evt.collection === ids.SiteStandardGraphSubscription) { if (evt.event === "create" || evt.event === "update") { diff --git a/lexicons/api/index.ts b/lexicons/api/index.ts index 79f21ed8..c1901c0a 100644 --- a/lexicons/api/index.ts +++ b/lexicons/api/index.ts @@ -56,6 +56,7 @@ import * as PubLeafletRichtextFacet from './types/pub/leaflet/richtext/facet' import * as PubLeafletThemeBackgroundImage from './types/pub/leaflet/theme/backgroundImage' import * as PubLeafletThemeColor from './types/pub/leaflet/theme/color' import * as SiteStandardDocument from './types/site/standard/document' +import * as SiteStandardGraphRecommend from './types/site/standard/graph/recommend' import * as SiteStandardGraphSubscription from './types/site/standard/graph/subscription' import * as SiteStandardPublication from './types/site/standard/publication' import * as SiteStandardThemeBasic from './types/site/standard/theme/basic' @@ -108,6 +109,7 @@ export * as PubLeafletRichtextFacet from './types/pub/leaflet/richtext/facet' export * as PubLeafletThemeBackgroundImage from './types/pub/leaflet/theme/backgroundImage' export * as PubLeafletThemeColor from './types/pub/leaflet/theme/color' export * as SiteStandardDocument from './types/site/standard/document' +export * as SiteStandardGraphRecommend from './types/site/standard/graph/recommend' export * as SiteStandardGraphSubscription from './types/site/standard/graph/subscription' export * as SiteStandardPublication from './types/site/standard/publication' export * as SiteStandardThemeBasic from './types/site/standard/theme/basic' @@ -1319,14 +1321,99 @@ export class SiteStandardNS { export class SiteStandardGraphNS { _client: XrpcClient + recommend: SiteStandardGraphRecommendRecord subscription: SiteStandardGraphSubscriptionRecord constructor(client: XrpcClient) { this._client = client + this.recommend = new SiteStandardGraphRecommendRecord(client) this.subscription = new SiteStandardGraphSubscriptionRecord(client) } } +export class SiteStandardGraphRecommendRecord { + _client: XrpcClient + + constructor(client: XrpcClient) { + this._client = client + } + + async list( + params: OmitKey, + ): Promise<{ + cursor?: string + records: { uri: string; value: SiteStandardGraphRecommend.Record }[] + }> { + const res = await this._client.call('com.atproto.repo.listRecords', { + collection: 'site.standard.graph.recommend', + ...params, + }) + return res.data + } + + async get( + params: OmitKey, + ): Promise<{ + uri: string + cid: string + value: SiteStandardGraphRecommend.Record + }> { + const res = await this._client.call('com.atproto.repo.getRecord', { + collection: 'site.standard.graph.recommend', + ...params, + }) + return res.data + } + + async create( + params: OmitKey< + ComAtprotoRepoCreateRecord.InputSchema, + 'collection' | 'record' + >, + record: Un$Typed, + headers?: Record, + ): Promise<{ uri: string; cid: string }> { + const collection = 'site.standard.graph.recommend' + const res = await this._client.call( + 'com.atproto.repo.createRecord', + undefined, + { collection, ...params, record: { ...record, $type: collection } }, + { encoding: 'application/json', headers }, + ) + return res.data + } + + async put( + params: OmitKey< + ComAtprotoRepoPutRecord.InputSchema, + 'collection' | 'record' + >, + record: Un$Typed, + headers?: Record, + ): Promise<{ uri: string; cid: string }> { + const collection = 'site.standard.graph.recommend' + const res = await this._client.call( + 'com.atproto.repo.putRecord', + undefined, + { collection, ...params, record: { ...record, $type: collection } }, + { encoding: 'application/json', headers }, + ) + return res.data + } + + async delete( + params: OmitKey, + headers?: Record, + ): Promise { + await this._client.call( + 'com.atproto.repo.deleteRecord', + undefined, + { collection: 'site.standard.graph.recommend', ...params }, + { headers }, + ) + } +} + export class SiteStandardGraphSubscriptionRecord { _client: XrpcClient diff --git a/lexicons/api/lexicons.ts b/lexicons/api/lexicons.ts index 6be2d1c4..38a10025 100644 --- a/lexicons/api/lexicons.ts +++ b/lexicons/api/lexicons.ts @@ -2602,6 +2602,33 @@ export const schemaDict = { id: 'site.standard.document', lexicon: 1, }, + SiteStandardGraphRecommend: { + id: 'site.standard.graph.recommend', + defs: { + main: { + key: 'tid', + type: 'record', + record: { + type: 'object', + required: ['document', 'createdAt'], + properties: { + document: { + type: 'string', + format: 'at-uri', + description: + 'AT-URI reference to the document record being recommended (ex: at://did:plc:abc123/site.standard.document/xyz789).', + }, + createdAt: { + type: 'string', + format: 'datetime', + }, + }, + }, + description: 'Record declaring a recommendation of a document.', + }, + }, + lexicon: 1, + }, SiteStandardGraphSubscription: { defs: { main: { @@ -2856,6 +2883,7 @@ export const ids = { PubLeafletThemeBackgroundImage: 'pub.leaflet.theme.backgroundImage', PubLeafletThemeColor: 'pub.leaflet.theme.color', SiteStandardDocument: 'site.standard.document', + SiteStandardGraphRecommend: 'site.standard.graph.recommend', SiteStandardGraphSubscription: 'site.standard.graph.subscription', SiteStandardPublication: 'site.standard.publication', SiteStandardThemeBasic: 'site.standard.theme.basic', -- 2.51.2