Changeset 09fc5fb in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 08/10/2026 02:03:09 PM (4 weeks ago)
- Branches:
- main
- Children:
- f549cf5
- Parents:
- 86ec01b
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r86ec01b r09fc5fb 4191 4191 } 4192 4192 4193 // ── Gesprekken: eerst wie, dan pas wat (shaer-frontend-yso) ────────── 4194 // 4195 // De oude lezing gaf de nieuwste 60 berichten over ALLE gesprekken samen. Dat 4196 // knipt geschiedenis weg zonder dat iemand het merkt, en het is bij DM's veel 4197 // erger dan bij posts: dat zijn er meer en het zijn kortere berichten, dus een 4198 // druk gesprek kan de 60 in zijn eentje opeten en de rest uit de lezing duwen. 4199 // Viel het laatste bericht van iemand erbuiten, dan verdween die persoon 4200 // helemaal uit Messages -- de avatarhemel plaatst mensen op de leeftijd van hun 4201 // laatste bericht, dus geen bericht is geen gezicht. 4202 // 4203 // Vandaar twee lezingen. Deze geeft EEN rij per tegenpartij, hoe druk iemand 4204 // ook is, en conversationHistory hieronder geeft het gesprek zelf met een 4205 // cursor. Wat de client van de hemel nodig heeft -- wie, wanneer, en waarmee -- 4206 // zit in die ene nieuwste note. 4207 // 4208 // Een gesprek is hier hetzelfde als in de app: incoming zijn de ap_mentions 4209 // (die tabel IS de aan ons gerichte post), uitgaand zijn de eigen notes met 4210 // visibility 'direct'. Een publiek antwoord is geen gesprek en hoort niet als 4211 // gezicht in de hemel. 4212 const GESPREK_UNIE = ` 4213 SELECT m.actor_uri AS other, COALESCE(m.published, m.created_at) AS stamp, 4214 'in' AS richting, m.object_uri AS ref 4215 FROM ap_mentions m 4216 WHERE m.slug = @slug AND m.actor_uri IS NOT NULL AND m.actor_uri <> '' 4217 UNION ALL 4218 SELECT j.value AS other, o.created_at AS stamp, 4219 'uit' AS richting, o.id AS ref 4220 FROM ap_outbox o 4221 JOIN json_each(COALESCE(NULLIF(o.to_actors, ''), json_array(o.to_actor))) j 4222 WHERE o.site_slug = @slug AND o.visibility = 'direct' 4223 AND j.value IS NOT NULL AND j.value <> ''`; 4224 4225 /** 4226 * Een rij per tegenpartij: zijn nieuwste bericht, nieuwste gesprek eerst. 4227 * 4228 * Compleet van vorm -- het aantal rijen is het aantal mensen, niet het aantal 4229 * berichten -- dus de hemel kan niemand meer kwijtraken doordat een ander druk 4230 * was. Zonder limiet, en dat mag: dit schaalt met je kring. 4231 */ 4232 export function conversationHeads(slug) { 4233 try { 4234 return db.prepare(` 4235 SELECT other, stamp, richting, ref FROM ( 4236 SELECT *, ROW_NUMBER() OVER (PARTITION BY other ORDER BY stamp DESC, ref DESC) AS rn 4237 FROM (${GESPREK_UNIE}) 4238 ) WHERE rn = 1 4239 ORDER BY stamp DESC, ref DESC`).all({ slug }); 4240 } catch { return []; } 4241 } 4242 4243 /** 4244 * Een gesprek, nieuwste eerst, met een cursor. 4245 * 4246 * BEIDE KANTEN ONDER EEN LIMIET. In de oude lezing werden jouw kant 4247 * (getSentNotes) en hun kant apart afgekapt, waardoor een gesprek eenzijdig 4248 * kon lijken -- alsof iemand nooit geantwoord had. Hier is de limiet er een 4249 * voor het gesprek als geheel. 4250 * 4251 * `before` is de cursor van het OUDSTE bericht dat je al hebt; je krijgt wat 4252 * daarvoor ligt. Er komt er een extra op om te weten of er nog meer is: de 4253 * client hoort dat te weten zonder te moeten gokken, en zonder dat weten kan 4254 * 'load more' niet eerlijk verschijnen. 4255 * 4256 * DE CURSOR IS SAMENGESTELD -- '<stempel>|<ref>' -- en niet alleen de stempel. 4257 * Twee berichten in dezelfde seconde is bij DM's geen randgeval maar een 4258 * gesprek, en met 'stamp < before' zou alles wat die grensseconde deelt stil 4259 * overgeslagen worden. Je zou het niet merken: de pagina komt gewoon, er 4260 * ontbreekt alleen iets in het midden. 4261 */ 4262 const cursorVan = (r) => (r ? `${r.stamp}|${r.ref}` : null); 4263 4264 export function conversationHistory(slug, other, { before = null, limit = 60 } = {}) { 4265 try { 4266 const n = Math.min(Math.max(parseInt(limit, 10) || 60, 1), 200); 4267 const knip = String(before || '').indexOf('|'); 4268 const bStamp = before && knip > 0 ? String(before).slice(0, knip) : null; 4269 const bRef = before && knip > 0 ? String(before).slice(knip + 1) : null; 4270 const rijen = db.prepare(` 4271 SELECT other, stamp, richting, ref FROM (${GESPREK_UNIE}) 4272 WHERE other = @other 4273 AND (@bStamp IS NULL OR stamp < @bStamp OR (stamp = @bStamp AND ref < @bRef)) 4274 ORDER BY stamp DESC, ref DESC LIMIT @n`).all({ slug, other, bStamp, bRef, n: n + 1 }); 4275 const meer = rijen.length > n; 4276 const uit = meer ? rijen.slice(0, n) : rijen; 4277 return { rijen: uit, meer, oudste: cursorVan(uit[uit.length - 1]) }; 4278 } catch { return { rijen: [], meer: false, oudste: null }; } 4279 } 4280 4281 // De kolommen die een bericht tot kaart maken. Een constante, want de 4282 // gesprekslezing haalt dezelfde rijen op: twee lijsten die uiteenlopen leveren 4283 // een kaart die op de ene plek een plaatje heeft en op de andere niet. 4284 const BERICHT_KOLOMMEN = ` 4285 m.object_uri, m.note_url, m.actor_uri, m.actor_name, m.actor_handle, m.actor_icon, m.actor_url, 4286 m.content, m.published, m.created_at, m.wave, m.help_request, 4287 m.emoji_json, m.actor_emoji_json, m.media_json, m.quote_json, m.embed_json`; 4288 4289 /** Dezelfde berichtrijen, maar op object-uri -- voor een gesprek. */ 4290 export function messageRowsByUri(slug, uris) { 4291 const lijst = (uris || []).filter((u) => typeof u === 'string' && u); 4292 if (!lijst.length) return []; 4293 try { 4294 const gaten = lijst.map(() => '?').join(','); 4295 return db.prepare(`SELECT ${BERICHT_KOLOMMEN} FROM ap_mentions m 4296 WHERE m.slug = ? AND m.object_uri IN (${gaten})`).all(slug, ...lijst); 4297 } catch { return []; } 4298 } 4299 4193 4300 export function getDirectMessages(slug, limit) { 4194 4301 try { 4195 4302 return db.prepare(` 4196 SELECT m.object_uri, m.note_url, m.actor_uri, m.actor_name, m.actor_handle, m.actor_icon, m.actor_url, 4197 m.content, m.published, m.created_at, m.wave, m.help_request, 4198 m.emoji_json, m.actor_emoji_json, m.media_json, m.quote_json, m.embed_json 4303 SELECT ${BERICHT_KOLOMMEN} 4199 4304 FROM ap_mentions m 4200 4305 WHERE m.slug = ? … … 6286 6391 getInteractions, getInteractionById, setInteractionBoosted, setInteractionLiked, buildReplyNote, getOutboxNote, getSentNotes, deliverReply, resolveRemoteNote, noteAudience, mayReadNote, 6287 6392 listOutbox, deliverOutboxDelete, deliverOutboxUpdate, deliverDirectNote, 6288 webfingerResolve, followActor, resolveRemoteActor, unfollowActor, handleMoveInbox, moveAccount, listFollowing, setAutoBoost, backfillFromOutbox, getTimeline, getDirectMessages, isoStamp, timelineAttachments, timelineEmojis, timelineObjectLinks, timelineQuote, timelineEmbed, applyQuoteProps, deliverToActor, sendInteraction, voteOnPoll, voteOnRemotePoll,6393 webfingerResolve, followActor, resolveRemoteActor, unfollowActor, handleMoveInbox, moveAccount, listFollowing, setAutoBoost, backfillFromOutbox, getTimeline, getDirectMessages, messageRowsByUri, conversationHeads, conversationHistory, isoStamp, timelineAttachments, timelineEmojis, timelineObjectLinks, timelineQuote, timelineEmbed, applyQuoteProps, deliverToActor, sendInteraction, voteOnPoll, voteOnRemotePoll, 6289 6394 acceptGatedFollow, rejectGatedFollow, isWardGuardian, outboxAudience, sendFollowDecision, 6290 6395 gateOutgoingFollow, performApprovedFollow, recordGuardianEvent, listGuardianEvents, GUARDIAN_EVENT_KEEP,
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)