diff --git a/appview/index.ts b/appview/index.ts index d5f86e27..22efb2bc 100644 --- a/appview/index.ts +++ b/appview/index.ts @@ -28,6 +28,7 @@ import { import { AtUri } from "@atproto/syntax"; import { writeFile, readFile } from "fs/promises"; import { inngest } from "app/api/inngest/client"; +import { stripThemeWithoutType } from "src/utils/stripThemeWithoutType"; const cursorFile = process.env.CURSOR_FILE || "/cursor/cursor"; @@ -359,17 +360,20 @@ async function handleEvent(evt: Event) { // site.standard.publication records go into the main "publications" table if (evt.collection === ids.SiteStandardPublication) { if (evt.event === "create" || evt.event === "update") { - let record = SiteStandardPublication.validateRecord(evt.record); + let record = SiteStandardPublication.validateRecord( + stripThemeWithoutType(evt.record), + ); if (!record.success) return; await supabase .from("identities") .upsert({ atp_did: evt.did }, { onConflict: "atp_did" }); - await supabase.from("publications").upsert({ + let { error } = await supabase.from("publications").upsert({ uri: evt.uri.toString(), identity_did: evt.did, name: record.value.name, record: record.value as Json, }); + if (error) console.log(error); } if (evt.event === "delete") { await supabase diff --git a/src/utils/stripThemeWithoutType.ts b/src/utils/stripThemeWithoutType.ts new file mode 100644 index 00000000..c1d493d8 --- /dev/null +++ b/src/utils/stripThemeWithoutType.ts @@ -0,0 +1,20 @@ +/** + * site.standard.publication records carry an optional `theme` field that the + * lexicon types as a union requiring a `$type` discriminator. Some records in + * the wild have a `theme` object missing `$type`, which makes + * `validateRecord` reject the entire publication — dropping it from the index. + * + * Strip a malformed (no-`$type`) theme so the rest of the record can still be + * validated and indexed. Returns the record unchanged when there's nothing to + * strip, and never mutates the input. + */ +export function stripThemeWithoutType(record: T): T { + if (record && typeof record === "object" && "theme" in record) { + const theme = (record as Record).theme; + if (theme && typeof theme === "object" && !("$type" in theme)) { + const { theme: _theme, ...rest } = record as Record; + return rest as T; + } + } + return record; +}