social components inlay.at
atproto components sdui
86
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 135 lines 3.8 kB view raw
1// data/actions.ts 2// Write mutations — all scoped to a verified DID 3import "server-only"; 4import { eq } from "drizzle-orm"; 5import { getDb, components, canvases, userPreferences } from "./db"; 6import type { CanvasRecord } from "./types"; 7 8// ============================================================================= 9// Component mutations 10// ============================================================================= 11 12export async function upsertComponent( 13 uri: string, 14 authorDid: string, 15 record: Record<string, unknown> 16): Promise<void> { 17 const db = getDb(); 18 const now = new Date(); 19 20 // Verify ownership if record exists 21 const existing = await db.query.components.findFirst({ 22 where: eq(components.uri, uri), 23 columns: { authorDid: true }, 24 }); 25 if (existing && existing.authorDid !== authorDid) { 26 throw new Error("Cannot modify another user's component"); 27 } 28 29 await db 30 .insert(components) 31 .values({ uri, cid: "pending", authorDid, record, createdAt: now }) 32 .onConflictDoUpdate({ 33 target: components.uri, 34 set: { cid: "pending", record, indexedAt: now }, 35 }); 36} 37 38export async function deleteComponent( 39 uri: string, 40 authorDid: string 41): Promise<Record<string, unknown> | null> { 42 const db = getDb(); 43 44 // Verify ownership 45 const existing = await db.query.components.findFirst({ 46 where: eq(components.uri, uri), 47 columns: { authorDid: true, record: true }, 48 }); 49 if (!existing) return null; 50 if (existing.authorDid !== authorDid) { 51 throw new Error("Cannot delete another user's component"); 52 } 53 54 await db.delete(components).where(eq(components.uri, uri)); 55 return existing.record as Record<string, unknown>; 56} 57 58// ============================================================================= 59// Canvas mutations 60// ============================================================================= 61 62export async function upsertCanvas( 63 uri: string, 64 authorDid: string, 65 record: CanvasRecord 66): Promise<void> { 67 const db = getDb(); 68 const now = new Date(); 69 70 const existing = await db.query.canvases.findFirst({ 71 where: eq(canvases.uri, uri), 72 columns: { authorDid: true }, 73 }); 74 if (existing && existing.authorDid !== authorDid) { 75 throw new Error("Cannot modify another user's canvas"); 76 } 77 78 await db 79 .insert(canvases) 80 .values({ 81 uri, 82 cid: "pending", 83 authorDid, 84 record, 85 createdAt: record.createdAt ? new Date(record.createdAt) : now, 86 }) 87 .onConflictDoUpdate({ 88 target: canvases.uri, 89 set: { cid: "pending", record, indexedAt: now }, 90 }); 91} 92 93export async function deleteCanvas( 94 uri: string, 95 authorDid: string 96): Promise<void> { 97 const db = getDb(); 98 99 const existing = await db.query.canvases.findFirst({ 100 where: eq(canvases.uri, uri), 101 columns: { authorDid: true }, 102 }); 103 if (!existing) return; 104 if (existing.authorDid !== authorDid) { 105 throw new Error("Cannot delete another user's canvas"); 106 } 107 108 await db.delete(canvases).where(eq(canvases.uri, uri)); 109} 110 111// ============================================================================= 112// User preferences mutations 113// ============================================================================= 114 115export async function saveValTownToken( 116 did: string, 117 token: string 118): Promise<void> { 119 const db = getDb(); 120 await db 121 .insert(userPreferences) 122 .values({ did, valTownToken: token, updatedAt: new Date() }) 123 .onConflictDoUpdate({ 124 target: userPreferences.did, 125 set: { valTownToken: token, updatedAt: new Date() }, 126 }); 127} 128 129export async function clearValTownToken(did: string): Promise<void> { 130 const db = getDb(); 131 await db 132 .update(userPreferences) 133 .set({ valTownToken: null, updatedAt: new Date() }) 134 .where(eq(userPreferences.did, did)); 135}