Ignore:
Timestamp:
09/23/2026 03:13:00 PM (2 hours ago)
Author:
Bart <bart@…>
Branches:
main
Parents:
0ad37a0
Message:

Een foto zonder woorden is een bericht (502 direct_failed)

deliverDirectNote begon met !String(text).trim() -> return null, en de inname
maakte van dat null een 502 direct_failed. Sinds de inname een bijlage-only
note doorlaat waren die twee lagen het oneens over wat een bericht is: wie een
foto op een gesprek liet vallen en niets typte kwam precies daar vast te
zitten. Het viel niet op in de tests, want dit was de enige plek waar de regel
stond en hij stond midden in een functie die netwerk doet.

Nu is het een eigen, pure regel -- text, html of bijlage -- met tests eromheen,
zoals de rest van deze laag het doet. Leeg blijft geweigerd: geen tekst, geen
opmaak en geen bijlage is niets.

En String(text) werd String(text || ''): zonder tekst stond er anders
letterlijk "undefined" in de body zodra een aanroeper het veld wegliet.

Co-Authored-By: Claude Opus 5 <claude@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/guardianship/delivery.js

    r0ad37a0 r407353e  
    3535}
    3636
     37/**
     38 * Heeft dit directe bericht iets te zeggen? Puur, zodat de regel te toetsen is
     39 * zonder database, netwerk of scherm.
     40 *
     41 * EEN FOTO KAN HET HELE BERICHT ZIJN. Hier stond alleen `!text.trim()`, en dat
     42 * betekende: een direct bericht zonder woorden gaf null terug, waar de inname
     43 * "502 direct_failed" van maakte. Precies wat je kreeg als je een foto op een
     44 * gesprek liet vallen en niets typte -- de inname liet een bijlage-only note
     45 * door, en deze laag eronder weigerde hem alsnog. Twee lagen die het niet eens
     46 * waren over wat een bericht is.
     47 *
     48 * Een leeg bericht blijft geweigerd: geen tekst, geen opmaak en geen bijlage is
     49 * niets, en dat hoort niet de deur uit te gaan.
     50 */
     51export function directNoteHasContent({ text, html, attachments } = {}) {
     52  if (String(text || '').trim()) return true;
     53  if (String(html || '').trim()) return true;
     54  return Array.isArray(attachments) && attachments.length > 0;
     55}
     56
    3757// A direct note: a NEW conversation (or a direct reply) addressed to specific
    3858// actors only. Stored in ap_outbox with visibility 'direct' + the recipient
     
    5373  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
    5474  const list = [...new Set((recipients || []).filter((u) => /^https?:\/\//i.test(String(u || ''))))].slice(0, 8);
    55   if (!base || !site || !site.slug || !list.length || !String(text || '').trim()) return null;
     75  if (!base || !site || !site.slug || !list.length) return null;
     76  if (!directNoteHasContent({ text, html, attachments })) return null;
    5677  const me = actorId(base, site.slug);
    5778  // Resolve every recipient for a mention anchor + a delivery inbox.
     
    108129  const richClean = html ? deps.sanitizeHtml(String(html)) : '';
    109130  const rich = richClean && deps.htmlToPlainText(richClean).trim() ? richClean : '';
    110   const body = escHtml(String(text).trim()).replace(/\r?\n/g, '<br>');
     131  const body = escHtml(String(text || '').trim()).replace(/\r?\n/g, '<br>');
    111132  // De mention-anker blijft een eigen alinea vooraan: de ontvanger moet in het
    112133  // bericht genoemd staan, ook als de rijke inhoud met een kop of lijst begint.
Note: See TracChangeset for help on using the changeset viewer.