[READ ONLY MIRROR] Spark Social AppView Server
github.com/sprksocial/server
atproto
deno
hono
lexicon
1import { Cid } from "@atp/lex";
2import { AtUri, normalizeDatetimeAlways } from "@atp/syntax";
3import * as so from "../../../lex/so.ts";
4import { BackgroundQueue } from "../../background.ts";
5import { Database } from "../../db/index.ts";
6import { GeneratorDocument } from "../../db/models.ts";
7import { RecordProcessor } from "../processor.ts";
8
9const schema = so.sprk.feed.generator.main;
10type FeedGeneratorRecord = so.sprk.feed.generator.Main;
11type IndexedFeedGenerator = GeneratorDocument;
12
13const insertFn = async (
14 db: Database,
15 uri: AtUri,
16 cid: Cid,
17 obj: FeedGeneratorRecord,
18 timestamp: string,
19): Promise<IndexedFeedGenerator | null> => {
20 // Extract and clean avatar to ensure it matches MediaRef format
21 const avatar = obj.avatar
22 ? {
23 $type: "blob",
24 ref: (obj.avatar as unknown as Record<string, unknown>)?.ref || null,
25 }
26 : null;
27
28 const generator = {
29 uri: uri.toString(),
30 cid: cid.toString(),
31 authorDid: uri.host,
32 did: obj.did,
33 displayName: obj.displayName,
34 description: obj.description || null,
35 descriptionFacets: obj.descriptionFacets || null,
36 avatar,
37 acceptsInteractions: obj.acceptsInteractions || null,
38 labels: null, // Will be populated by label processing
39 createdAt: normalizeDatetimeAlways(obj.createdAt),
40 indexedAt: timestamp,
41 };
42
43 const insertedGenerator = await db.models.Generator.findOneAndUpdate(
44 { uri: generator.uri },
45 { $set: generator },
46 { upsert: true, returnDocument: "after" },
47 );
48 return insertedGenerator;
49};
50
51const findDuplicate = (): AtUri | null => {
52 return null;
53};
54
55const notifsForInsert = () => {
56 return [];
57};
58
59const deleteFn = async (
60 db: Database,
61 uri: AtUri,
62): Promise<IndexedFeedGenerator | null> => {
63 const deleted = await db.models.Generator.findOneAndDelete({
64 uri: uri.toString(),
65 });
66 return deleted;
67};
68
69const notifsForDelete = () => {
70 return { notifs: [], toDelete: [] };
71};
72
73export type PluginType = RecordProcessor<
74 typeof schema,
75 IndexedFeedGenerator
76>;
77
78export const makePlugin = (
79 db: Database,
80 background: BackgroundQueue,
81): PluginType => {
82 return new RecordProcessor(db, background, {
83 schema,
84 insertFn,
85 findDuplicate,
86 deleteFn,
87 notifsForInsert,
88 notifsForDelete,
89 });
90};
91
92export default makePlugin;