aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-13 13:04:52 +0000
committerAdam Soltys <[email protected]>2026-10-13 13:04:52 +0000
commitf3d03c642bef06b3afc8a3038136c5e0fc1e21f7 (patch)
tree11f43f80c14d9c712d12ba86820ca38fa51b9bf1 /src/features/messages.js
parentcd058495e11d76bb5afe4fe85b5131adaa387ca1 (diff)
downloadcoinosv3-f3d03c642bef06b3afc8a3038136c5e0fc1e21f7.tar.gz
coinosv3-f3d03c642bef06b3afc8a3038136c5e0fc1e21f7.zip
Profiles show boosts as boosts, and their saved copy keeps each post's kind
A boost that reached a profile from the feed was saved as a kind 1 note, so reopened it drew its raw JSON as a reply; video events and polls lost their kind and tags the same way. The saved copy now keeps kinds (boosts whole), old copies are dropped, and profiles ask for boosts too. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js18
1 files changed, 14 insertions, 4 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index 1d9fd61..3cb94fd 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -566,7 +566,8 @@ export function messagesFeature(ctx) {
}
let repostBy = null; // set while noteRow draws a repost's note
// A profile shows its articles (NIP-23) among the notes, as Amethyst does.
- const PROFILE_KINDS = [...FEED_KINDS, 30023];
+ // Their boosts too, under "<name> reposted", as in a feed.
+ const PROFILE_KINDS = [...FEED_KINDS, 30023, REPOST];
// An edited article is a new event at the same address: keep the newest.
const newestArticles = (evs) => {
const best = new Map();
@@ -3825,13 +3826,16 @@ export function messagesFeature(ctx) {
const pageCache = () => {
try {
const c = wallet.loadFeatureState(PROF_PAGE_CACHE, {}) || {};
- return { full: c.full || {}, notes: c.notes || {} };
+ // (notes saved before nv 2 were all flattened to kind 1: a boost's
+ // JSON, a clip without its imeta — not worth keeping)
+ return { full: c.full || {}, notes: c.nv === 2 ? c.notes || {} : {} };
} catch { return { full: {}, notes: {} }; }
};
function persistPage(kind, pk, value) {
try {
const c = pageCache();
c[kind][pk] = { t: Date.now(), v: value };
+ c.nv = 2;
for (const k of ['full', 'notes']) {
const keys = Object.keys(c[k]).sort((a, b) => c[k][b].t - c[k][a].t);
for (const drop of keys.slice(10)) delete c[k][drop];
@@ -3842,14 +3846,20 @@ export function messagesFeature(ctx) {
// (an article keeps its kind, its card's tags and, near enough, all of
// itself: a tap opens it to read)
const ARTICLE_TAGS = ['d', 'title', 'summary', 'image', 'published_at'];
+ // (a note keeps its kind and what draws it: its clips, a poll's options)
+ const NOTE_TAGS = ['e', 'p', 'q', 'd', 'imeta', 'title', 'option', 'polltype', 'endsAt', 'relay', 'emoji', 'content-warning'];
const slimNote = (ev) => ev.kind === 30023 ? {
id: ev.id, pubkey: ev.pubkey, kind: 30023, created_at: ev.created_at,
content: String(ev.content || '').slice(0, 30000),
tags: (ev.tags || []).filter((x) => ARTICLE_TAGS.includes(x[0])),
+ } : ev.kind === REPOST ? {
+ // a boost whole: the note inside is checked against its signature
+ id: ev.id, pubkey: ev.pubkey, kind: REPOST, created_at: ev.created_at,
+ content: String(ev.content || ''), tags: (ev.tags || []).filter((x) => x[0] === 'e' || x[0] === 'p'),
} : {
- id: ev.id, pubkey: ev.pubkey, kind: 1, created_at: ev.created_at,
+ id: ev.id, pubkey: ev.pubkey, kind: ev.kind, created_at: ev.created_at,
content: String(ev.content || '').slice(0, 3000),
- tags: (ev.tags || []).filter((x) => x[0] === 'e' || x[0] === 'p'),
+ tags: (ev.tags || []).filter((x) => NOTE_TAGS.includes(x[0])),
};
function fetchFullProfile(pk) {