Changeset f59a46c in Klonkt


Ignore:
Timestamp:
08/13/2026 01:09:24 PM (4 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
013e16c
Parents:
6401681
git-author:
Robin <roboburr@…> (08/13/2026 12:52:57 PM)
git-committer:
Robin <roboburr@…> (08/13/2026 01:09:24 PM)
Message:

Stap 3: de koppeling gaat de draad op als schema:sameAs (shaer-mbz)

Alleen als de artiest ZELF gekozen heeft. Staat er niets, dan staat er niets --
een lege of geraden verwijzing is erger dan geen.

WAAROM sameAs EN NIET alsoKnownAs, en dat is geen smaakkwestie. alsoKnownAs is
in AS2 gereserveerd voor vroegere IDENTITEITEN van dezelfde actor, en FEP-7628
leunt erop bij een verhuizing: het oude adres controleert of het nieuwe hem daar
noemt voordat het volgers meegeeft. Een MBID daartussen zetten zou een
verhuizing kunnen laten mislukken. schema:sameAs zegt precies het goede: dit
ding is ook bekend onder die URI.

Geen nieuwe namespace: schema stond al in onze context, naast license, position
en bitrate. Dit is er een termregel bij.

EEN KRINGLOOP VERMEDEN. MusicBrainzService leent safeFetch uit
ActivityPubService, dus die er andersom uit laten importeren zou een cirkel
maken. isMbid en artiestUrl zijn pure vormcontroles zonder afhankelijkheden en
wonen nu in ap-core -- dezelfde plek en dezelfde reden als de tagparsers van
gisteren. MusicBrainzService exporteert ze her, zodat een aanroeper er niet over
hoeft na te denken.

DE ACTOR IS DE LAATSTE DEUR. Het scherm zeeft al op een echte MBID, maar
artiestUrl doet het nog een keer: wat hier langskomt gaat naar iedereen, en een
half adres is erger dan geen. Een test zet met opzet rommel in de kolom en eist
dat er niets naar buiten gaat.

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

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r6401681 rf59a46c  
    2929import Blocklist from './BlocklistService.js';
    3030import * as Guardianship from './guardianship/index.js';
    31 import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType, normalizeTags, tagParts, hashtagTags, buildHashtagList, pagedCollection, PAGINA_GROOTTE } from './ap-core.js';
     31import { PUBLIC, AP_CONTEXT, safeUrl, actorId, noteId, guessMediaType, normalizeTags, tagParts, hashtagTags, buildHashtagList, pagedCollection, PAGINA_GROOTTE, artiestUrl } from './ap-core.js';
    3232// Doorgeven wat hier altijd vandaan kwam, zodat elke bestaande aanroep blijft werken.
    3333export { AP_CONTEXT, actorId, noteId, guessMediaType };
     
    394394  // and publishers should stop delivering here.
    395395  if (site.moved_to && /^https?:\/\//i.test(String(site.moved_to))) actor.movedTo = String(site.moved_to);
     396  // De MusicBrainz-koppeling van de artiest (shaer-mbz). Alleen als hij ZELF
     397  // gekozen heeft -- er staat niets als er niets gekoppeld is, want een lege
     398  // of geraden verwijzing is erger dan geen.
     399  //
     400  // schema:sameAs en niet alsoKnownAs: dat laatste is in AS2 voor vroegere
     401  // identiteiten van dezelfde actor, en FEP-7628 leunt erop bij een verhuizing.
     402  // Een MBID hier neerzetten zou een verhuizing kunnen laten mislukken.
     403  const mbUrl = artiestUrl(site.mb_artist_id);
     404  if (mbUrl) actor.sameAs = mbUrl;
    396405  // Profile links → PropertyValue rows: Mastodon/PeerTube/WordPress-ActivityPub render these as
    397406  // profile metadata (rel=me enables link-back verification). Additive; ignored by simpler receivers.
  • src/services/MusicBrainzService.js

    r6401681 rf59a46c  
    2020 */
    2121import { safeFetch } from './ActivityPubService.js';
     22// De twee pure vormcontroles wonen in ap-core: ActivityPubService heeft ze ook
     23// nodig voor de actor, en zonder die verhuizing zou dat een KRINGLOOP zijn --
     24// deze module leent immers safeFetch dáár.
     25import { isMbid, artiestUrl } from './ap-core.js';
    2226
    2327const BASIS = 'https://musicbrainz.org/ws/2';
     
    97101}
    98102
    99 /** Is dit een MBID? Een UUID, en niets anders. */
    100 export function isMbid(s) {
    101   return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(String(s || '').trim());
    102 }
    103 
    104 /** De publieke pagina van een artiest, of null als het geen MBID is. */
    105 export function artiestUrl(mbid) {
    106   return isMbid(mbid) ? `https://musicbrainz.org/artist/${String(mbid).trim().toLowerCase()}` : null;
    107 }
    108 
     103// Her-geexporteerd zodat een aanroeper er niet over hoeft na te denken waar
     104// ze precies wonen.
     105export { isMbid, artiestUrl };
    109106export default { zoekArtiesten, isMbid, artiestUrl };
  • src/services/ap-core.js

    r6401681 rf59a46c  
    5050    // schema.org, dus we hoeven geen vreemd vocabulaire binnen te halen.
    5151    license: { '@id': 'schema:license', '@type': '@id' },
     52    // "Dit ding is ook bekend onder die URI" -- voor de MusicBrainz-koppeling
     53    // van een artiest (shaer-mbz). Bewust NIET alsoKnownAs: dat is in AS2
     54    // gereserveerd voor vroegere IDENTITEITEN van dezelfde actor, en een
     55    // verhuizing leunt erop (FEP-7628). Een verwijzing naar een register is
     56    // iets anders dan een oud account van jezelf, en die twee door elkaar halen
     57    // zou een verhuizing kunnen laten mislukken.
     58    sameAs: { '@id': 'schema:sameAs', '@type': '@id' },
    5259    position: 'schema:position',
    5360    bitrate: 'schema:bitrate',
     
    268275  };
    269276}
     277
     278/** Is dit een MBID? Een UUID, en niets anders. */
     279export function isMbid(s) {
     280  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(String(s || '').trim());
     281}
     282
     283/** De publieke pagina van een artiest, of null als het geen MBID is. */
     284export function artiestUrl(mbid) {
     285  return isMbid(mbid) ? `https://musicbrainz.org/artist/${String(mbid).trim().toLowerCase()}` : null;
     286}
  • test/musicbrainz.test.js

    r6401681 rf59a46c  
    124124  assert.equal(s.mb_artist_name, null, 'anders blijft er een naam staan zonder koppeling');
    125125});
     126
     127// ── Stap 3: op de draad ───────────────────────────────────────────────────
     128
     129test('de actor draagt sameAs zodra er gekoppeld is -- en anders niets', async () => {
     130  const db = dbMod.default;
     131  const AP = await import('../src/services/ActivityPubService.js');
     132  const BASE = 'https://ons.test';
     133  const kaal = db.prepare("SELECT * FROM sites WHERE id = 's1'").get();
     134  assert.equal(AP.buildActor(BASE, kaal).sameAs, undefined,
     135    'zonder koppeling staat er niets -- een lege verwijzing is erger dan geen');
     136
     137  db.prepare('UPDATE sites SET mb_artist_id = ? WHERE id = ?')
     138    .run('8be31978-1884-4773-beae-f73df35b92aa', 's1');
     139  const gekoppeld = db.prepare("SELECT * FROM sites WHERE id = 's1'").get();
     140  const actor = AP.buildActor(BASE, gekoppeld);
     141  assert.equal(actor.sameAs, 'https://musicbrainz.org/artist/8be31978-1884-4773-beae-f73df35b92aa');
     142});
     143
     144test('rommel in de kolom komt NIET op de draad', () => {
     145  // Het scherm zeeft al, maar de actor is de laatste deur. Wat hier langskomt
     146  // gaat naar iedereen, en een half adres is erger dan geen.
     147  const db = dbMod.default;
     148  db.prepare('UPDATE sites SET mb_artist_id = ? WHERE id = ?').run('nirvana', 's1');
     149  const s = db.prepare("SELECT * FROM sites WHERE id = 's1'").get();
     150  assert.equal(MB.artiestUrl(s.mb_artist_id), null);
     151});
     152
     153test('sameAs is een eigen term en NIET alsoKnownAs', async () => {
     154  // alsoKnownAs is in AS2 voor vroegere IDENTITEITEN van dezelfde actor, en
     155  // FEP-7628 leunt erop bij een verhuizing: het oude adres controleert of het
     156  // nieuwe hem daar noemt. Een MBID daar neerzetten zou een verhuizing kunnen
     157  // laten mislukken.
     158  const core = await import('../src/services/ap-core.js');
     159  const term = core.AP_CONTEXT.find((x) => x && typeof x === 'object' && x.sameAs);
     160  assert.ok(term, 'de term is gedeclareerd, anders laat een strikte lezer hem vallen');
     161  assert.equal(term.sameAs['@id'], 'schema:sameAs');
     162  assert.equal(term.sameAs['@type'], '@id', 'het is een URI en geen tekst');
     163});
Note: See TracChangeset for help on using the changeset viewer.