From 33e5b201597161a46beb39edca226e1a754dc339 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 17 Oct 2024 15:04:57 -0500 Subject: [PATCH] Hydrate null authors --- src/queries.ts | 19 +++++++++++++------ src/storages/hydrate.ts | 4 +++- src/utils.ts | 26 +++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/queries.ts b/src/queries.ts index 3ca805a8..e93027d9 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -6,6 +6,7 @@ import { Storages } from '@/storages.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; import { type DittoRelation } from '@/interfaces/DittoFilter.ts'; import { hydrateEvents } from '@/storages/hydrate.ts'; +import { fallbackAuthor } from '@/utils.ts'; import { findReplyTag, getTagSet } from '@/utils/tags.ts'; const debug = Debug('ditto:queries'); @@ -38,15 +39,21 @@ const getEvent = async ( .then(([event]) => event); }; -/** Get a Nostr `set_medatadata` event for a user's pubkey. */ -const getAuthor = async (pubkey: string, opts: GetEventOpts = {}): Promise => { +/** + * Get a Nostr `set_medatadata` event for a user's pubkey. + * @deprecated Use `store.query` directly. + */ +async function getAuthor(pubkey: string, opts: GetEventOpts = {}): Promise { const store = await Storages.db(); const { signal = AbortSignal.timeout(1000) } = opts; - return await store.query([{ authors: [pubkey], kinds: [0], limit: 1 }], { limit: 1, signal }) - .then((events) => hydrateEvents({ events, store, signal })) - .then(([event]) => event); -}; + const events = await store.query([{ authors: [pubkey], kinds: [0], limit: 1 }], { limit: 1, signal }); + const event = events[0] ?? fallbackAuthor(pubkey); + + await hydrateEvents({ events: [event], store, signal }); + + return event; +} /** Get users the given pubkey follows. */ const getFollows = async (pubkey: string, signal?: AbortSignal): Promise => { diff --git a/src/storages/hydrate.ts b/src/storages/hydrate.ts index a30608ca..c8b9b97e 100644 --- a/src/storages/hydrate.ts +++ b/src/storages/hydrate.ts @@ -7,6 +7,7 @@ import { z } from 'zod'; import { DittoTables } from '@/db/DittoTables.ts'; import { Conf } from '@/config.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; +import { fallbackAuthor } from '@/utils.ts'; import { findQuoteTag } from '@/utils/tags.ts'; import { findQuoteInContent } from '@/utils/note.ts'; import { getAmount } from '@/utils/bolt11.ts'; @@ -98,7 +99,8 @@ export function assembleEvents( })); for (const event of a) { - event.author = b.find((e) => matchFilter({ kinds: [0], authors: [event.pubkey] }, e)); + event.author = b.find((e) => matchFilter({ kinds: [0], authors: [event.pubkey] }, e)) ?? + fallbackAuthor(event.pubkey); event.user = b.find((e) => matchFilter({ kinds: [30382], authors: [admin], '#d': [event.pubkey] }, e)); event.info = b.find((e) => matchFilter({ kinds: [30383], authors: [admin], '#d': [event.id] }, e)); diff --git a/src/utils.ts b/src/utils.ts index ae257374..a1298de9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -74,6 +74,30 @@ function isURL(value: unknown): boolean { return z.string().url().safeParse(value).success; } -export { bech32ToPubkey, eventAge, findTag, isNostrId, isURL, type Nip05, nostrDate, nostrNow, parseNip05 }; +/** Render an empty author event so other things can stick to it. */ +function fallbackAuthor(pubkey: string): NostrEvent { + return { + kind: 0, + pubkey, + content: '', + tags: [], + created_at: nostrNow(), + id: '', + sig: '', + }; +} + +export { + bech32ToPubkey, + eventAge, + fallbackAuthor, + findTag, + isNostrId, + isURL, + type Nip05, + nostrDate, + nostrNow, + parseNip05, +}; export { Time } from '@/utils/time.ts';