a tool for shared writing and social publishing

publish notifications again

+66 -17
+14 -15
app/lish/[did]/[publication]/[rkey]/Interactions/Comments/commentAction.ts
··· 8 8 import { AtUri, lexToJson, Un$Typed } from "@atproto/api"; 9 9 import { supabaseServerClient } from "supabase/serverClient"; 10 10 import { Json } from "supabase/database.types"; 11 + import { Notification } from "src/notifications"; 11 12 12 13 export async function publishComment(args: { 13 14 document: string; ··· 65 66 } as unknown as Json, 66 67 }) 67 68 .select(); 68 - // let notifications = [ 69 - // { 70 - // comment: uri.toString(), 71 - // identity: new AtUri(args.document).host, 72 - // reason: "reply-on-post", 73 - // }, 74 - // ]; 75 - // if (args.comment.replyTo) 76 - // notifications.push({ 77 - // comment: uri.toString(), 78 - // identity: new AtUri(args.comment.replyTo).host, 79 - // reason: "reply-to-comment", 80 - // }); 81 - // // SOMEDAY: move this out the action with inngest or workflows 82 - // await supabaseServerClient.from("notif_comments").insert(notifications); 69 + let notifications: Notification[] = [ 70 + { 71 + recipient: new AtUri(args.document).host, 72 + data: { type: "comment", comment_uri: uri.toString() }, 73 + }, 74 + ]; 75 + if (args.comment.replyTo) 76 + notifications.push({ 77 + recipient: new AtUri(args.comment.replyTo).host, 78 + data: { type: "comment", comment_uri: uri.toString() }, 79 + }); 80 + // SOMEDAY: move this out the action with inngest or workflows 81 + await supabaseServerClient.from("notifications").insert(notifications); 83 82 84 83 return { 85 84 record: data?.[0].record as Json,
+9 -1
drizzle/relations.ts
··· 1 1 import { relations } from "drizzle-orm/relations"; 2 - import { identities, publications, documents, comments_on_documents, bsky_profiles, entity_sets, entities, facts, email_auth_tokens, poll_votes_on_entity, permission_tokens, phone_rsvps_to_entity, custom_domains, custom_domain_routes, email_subscriptions_to_entity, atp_poll_records, atp_poll_votes, bsky_follows, subscribers_to_publications, permission_token_on_homepage, documents_in_publications, document_mentions_in_bsky, bsky_posts, publication_domains, leaflets_in_publications, publication_subscriptions, permission_token_rights } from "./schema"; 2 + import { identities, publications, documents, comments_on_documents, bsky_profiles, entity_sets, entities, facts, email_auth_tokens, poll_votes_on_entity, permission_tokens, phone_rsvps_to_entity, custom_domains, custom_domain_routes, email_subscriptions_to_entity, atp_poll_records, atp_poll_votes, notifications, bsky_follows, subscribers_to_publications, permission_token_on_homepage, documents_in_publications, document_mentions_in_bsky, bsky_posts, publication_domains, leaflets_in_publications, publication_subscriptions, permission_token_rights } from "./schema"; 3 3 4 4 export const publicationsRelations = relations(publications, ({one, many}) => ({ 5 5 identity: one(identities, { ··· 27 27 custom_domains_identity_id: many(custom_domains, { 28 28 relationName: "custom_domains_identity_id_identities_id" 29 29 }), 30 + notifications: many(notifications), 30 31 bsky_follows_follows: many(bsky_follows, { 31 32 relationName: "bsky_follows_follows_identities_atp_did" 32 33 }), ··· 191 192 192 193 export const atp_poll_recordsRelations = relations(atp_poll_records, ({many}) => ({ 193 194 atp_poll_votes: many(atp_poll_votes), 195 + })); 196 + 197 + export const notificationsRelations = relations(notifications, ({one}) => ({ 198 + identity: one(identities, { 199 + fields: [notifications.recipient], 200 + references: [identities.atp_did] 201 + }), 194 202 })); 195 203 196 204 export const bsky_followsRelations = relations(bsky_follows, ({one}) => ({
+14 -1
drizzle/schema.ts
··· 165 165 } 166 166 }); 167 167 168 + export const notification = pgTable("notification", { 169 + recipient: text("recipient").primaryKey().notNull(), 170 + created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 171 + read: boolean("read").default(false).notNull(), 172 + data: jsonb("data").notNull(), 173 + }); 174 + 168 175 export const custom_domain_routes = pgTable("custom_domain_routes", { 169 176 id: uuid("id").defaultRandom().primaryKey().notNull(), 170 177 domain: text("domain").notNull().references(() => custom_domains.domain), ··· 210 217 voter_did: text("voter_did").notNull(), 211 218 poll_uri: text("poll_uri").notNull().references(() => atp_poll_records.uri, { onDelete: "cascade", onUpdate: "cascade" } ), 212 219 poll_cid: text("poll_cid").notNull(), 213 - option: text("option").notNull(), 214 220 indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 215 221 }, 216 222 (table) => { ··· 230 236 export const oauth_session_store = pgTable("oauth_session_store", { 231 237 key: text("key").primaryKey().notNull(), 232 238 session: jsonb("session").notNull(), 239 + }); 240 + 241 + export const notifications = pgTable("notifications", { 242 + recipient: text("recipient").primaryKey().notNull().references(() => identities.atp_did, { onDelete: "cascade", onUpdate: "cascade" } ), 243 + created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 244 + read: boolean("read").default(false).notNull(), 245 + data: jsonb("data").notNull(), 233 246 }); 234 247 235 248 export const bsky_follows = pgTable("bsky_follows", {
+29
supabase/database.types.ts
··· 624 624 }, 625 625 ] 626 626 } 627 + notifications: { 628 + Row: { 629 + created_at: string 630 + data: Json 631 + read: boolean 632 + recipient: string 633 + } 634 + Insert: { 635 + created_at?: string 636 + data: Json 637 + read?: boolean 638 + recipient: string 639 + } 640 + Update: { 641 + created_at?: string 642 + data?: Json 643 + read?: boolean 644 + recipient?: string 645 + } 646 + Relationships: [ 647 + { 648 + foreignKeyName: "notifications_recipient_fkey" 649 + columns: ["recipient"] 650 + isOneToOne: true 651 + referencedRelation: "identities" 652 + referencedColumns: ["atp_did"] 653 + }, 654 + ] 655 + } 627 656 oauth_session_store: { 628 657 Row: { 629 658 key: string