From 9f81d0d57223da51a64c68614eb75c4827913f9d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 18 Mar 2023 16:30:46 -0500 Subject: [PATCH] Reuse existing transmute functions, lol forgot I already wrote that --- src/api/home.ts | 28 ++-------------------------- src/api/statuses.ts | 8 ++------ src/schema.ts | 13 ++++++++++++- src/transmute.ts | 38 +++++++++++++++++++++++++------------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/api/home.ts b/src/api/home.ts index 81995bf..f3174c8 100644 --- a/src/api/home.ts +++ b/src/api/home.ts @@ -2,7 +2,7 @@ import { fetchFeed, fetchFollows } from '../client.ts'; import { getKeys } from '../utils.ts'; import type { Context } from '@/deps.ts'; -import type { SignedEvent } from '../event.ts'; +import { toStatus } from '../transmute.ts'; async function homeController(c: Context) { const keys = getKeys(c); @@ -16,33 +16,9 @@ async function homeController(c: Context) { } const events = await fetchFeed(follows); - const statuses = events.map(toStatus); + const statuses = (await Promise.all(events.map(toStatus))).filter(Boolean); return c.json(statuses); } -interface Account { - id: string; - acct: string; - username: string; -} - -interface Status { - id: string; - content: string; - account: Account; -} - -function toStatus(event: SignedEvent<1>): Status { - return { - id: event.id, - content: event.content, - account: { - id: event.pubkey, - acct: event.pubkey, - username: event.pubkey, - }, - }; -} - export default homeController; diff --git a/src/api/statuses.ts b/src/api/statuses.ts index ed85991..c80c2d3 100644 --- a/src/api/statuses.ts +++ b/src/api/statuses.ts @@ -1,8 +1,7 @@ import { validator, z } from '@/deps.ts'; -import { fetchUser } from '../client.ts'; import publish from '../publisher.ts'; -import { toAccount, toStatus } from '../transmute.ts'; +import { toStatus } from '../transmute.ts'; import { getKeys } from '../utils.ts'; import type { Event } from '../event.ts'; @@ -29,10 +28,7 @@ const createStatusController = validator('json', async (value, c) => { publish(event, privatekey); - return c.json({ - ...toStatus(event), - account: toAccount((await fetchUser(pubkey))!), - }); + return c.json(await toStatus(event)); } else { return c.json({ error: 'Bad request' }, 400); } diff --git a/src/schema.ts b/src/schema.ts index 3d35f25..639d390 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,5 +1,16 @@ import { z } from '@/deps.ts'; +const jsonSchema = z.string().refine((value) => { + try { + // FIXME: this calls JSON.parse twice. Can we make it not do that? + // https://github.com/colinhacks/zod/discussions/2215 + JSON.parse(value); + return true; + } catch (_) { + return false; + } +}).transform((value) => JSON.parse(value)); + const optionalString = z.string().optional().catch(undefined); const metaContentSchema = z.object({ @@ -13,5 +24,5 @@ const metaContentSchema = z.object({ type MetaContent = z.infer; -export { metaContentSchema }; +export { jsonSchema, metaContentSchema }; export type { MetaContent }; diff --git a/src/transmute.ts b/src/transmute.ts index 91ddea1..4cba0c9 100644 --- a/src/transmute.ts +++ b/src/transmute.ts @@ -1,19 +1,27 @@ import { LOCAL_DOMAIN } from './config.ts'; -import { MetaContent, metaContentSchema } from './schema.ts'; +import { fetchUser } from './client.ts'; +import { jsonSchema, MetaContent, metaContentSchema } from './schema.ts'; import type { Event } from './event.ts'; +const DEFAULT_AVATAR = 'https://gleasonator.com/images/avi.png'; + +function parseContent(event: Event<0>): MetaContent { + const json = jsonSchema.parse(event.content); + const result = metaContentSchema.safeParse(json); + return result.success ? result.data : {}; +} + function toAccount(event: Event<0>) { const { pubkey } = event; - const parsed = metaContentSchema.safeParse(JSON.parse(event?.content || '')); - const content: MetaContent = parsed.success ? parsed.data : {}; + const content: MetaContent = parseContent(event); const { host, origin } = new URL(LOCAL_DOMAIN); return { id: pubkey, - acct: pubkey, - avatar: content.picture, - avatar_static: content.picture, + acct: content.nip05 || pubkey, + avatar: content.picture || DEFAULT_AVATAR, + avatar_static: content.picture || DEFAULT_AVATAR, bot: false, created_at: event ? new Date(event.created_at * 1000).toISOString() : new Date().toISOString(), display_name: content.name, @@ -27,21 +35,25 @@ function toAccount(event: Event<0>) { header_static: content.banner, locked: false, note: content.about, - fqn: `${pubkey}@${host}`, + fqn: content.nip05 || `${pubkey}@${host}`, url: `${origin}/users/${pubkey}`, - username: pubkey, + username: content.nip05 || pubkey, }; } -function toStatus(event: Event<1>) { +async function toStatus(event: Event<1>) { + const profile = await fetchUser(event.pubkey); + const account = profile ? toAccount(profile) : undefined; + if (!account) return; + + const inReplyTo = event.tags.find((tag) => tag[0] === 'e' && tag[3] === 'reply'); + return { id: event.id, - account: { - id: event.pubkey, - }, + account, content: event.content, created_at: new Date(event.created_at * 1000).toISOString(), - in_reply_to_id: null, + in_reply_to_id: inReplyTo ? inReplyTo[1] : null, in_reply_to_account_id: null, sensitive: false, spoiler_text: '',